From fd2a5bc9f5be388122225e80aa8ca4ea08bf6e52 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 26 Jun 2016 00:34:39 +0200 Subject: [PATCH] Initial submission of the PCem-Experimental source code. --- AUTHORS | 0 COPYING | 339 ++ ChangeLog | 0 INSTALL | 1 + Makefile.am | 2 + Makefile.in | 670 ++++ NEWS | 0 README | 0 Readme-LINUX.txt | 31 + aclocal.m4 | 1179 ++++++ compile | 1 + config.guess | 1533 ++++++++ config.sub | 1693 +++++++++ configure | 5776 ++++++++++++++++++++++++++++++ configure.ac | 69 + depcomp | 1 + install-sh | 1 + missing | 1 + nvr/430vx.nvr | Bin 0 -> 152 bytes nvr/440fx.nvr | Bin 0 -> 152 bytes nvr/586mc1.nvr | Bin 0 -> 128 bytes nvr/acer386.nvr | Bin 0 -> 128 bytes nvr/acerm3a.nvr | Bin 0 -> 128 bytes nvr/acerv35n.nvr | Bin 0 -> 128 bytes nvr/adgold.bin | Bin 0 -> 24 bytes nvr/ami286.nvr | Bin 0 -> 128 bytes nvr/ami386.nvr | Bin 0 -> 128 bytes nvr/ami486.nvr | Bin 0 -> 128 bytes nvr/at.nvr | Bin 0 -> 128 bytes nvr/cmdpc30.nvr | Bin 0 -> 128 bytes nvr/dell200.nvr | Bin 0 -> 128 bytes nvr/deskpro386.nvr | Bin 0 -> 128 bytes nvr/dtk386.nvr | Bin 0 -> 152 bytes nvr/dtk486.nvr | Bin 0 -> 152 bytes nvr/endeavor.nvr | Bin 0 -> 152 bytes nvr/europc.nvr | Bin 0 -> 16 bytes nvr/hot-433.nvr | Bin 0 -> 128 bytes nvr/ibmps1_2011.nvr | Bin 0 -> 128 bytes nvr/ibmps1_2121.nvr | Bin 0 -> 152 bytes nvr/kn97.nvr | Bin 0 -> 152 bytes nvr/mb500n.nvr | Bin 0 -> 152 bytes nvr/megapc.nvr | Bin 0 -> 128 bytes nvr/p54tp4xe.nvr | Bin 0 -> 152 bytes nvr/p55t2p4.nvr | Bin 0 -> 152 bytes nvr/p55tp4n.nvr | Bin 0 -> 128 bytes nvr/p55tp4xe.nvr | Bin 0 -> 128 bytes nvr/p55tvp4.nvr | Bin 0 -> 152 bytes nvr/p55va.nvr | Bin 0 -> 152 bytes nvr/p5sp4.nvr | Bin 0 -> 128 bytes nvr/pc1512.nvr | Bin 0 -> 128 bytes nvr/pc1640.nvr | Bin 0 -> 128 bytes nvr/pc200.nvr | Bin 0 -> 152 bytes nvr/pc2086.nvr | Bin 0 -> 128 bytes nvr/pc3086.nvr | Bin 0 -> 128 bytes nvr/plato.nvr | Bin 0 -> 128 bytes nvr/px386.nvr | Bin 0 -> 152 bytes nvr/r418.nvr | Bin 0 -> 152 bytes nvr/revenge.nvr | Bin 0 -> 152 bytes nvr/sis496.nvr | Bin 0 -> 152 bytes nvr/tandy1000hx.bin | Bin 0 -> 128 bytes nvr/tandy1000sl2.bin | Bin 0 -> 128 bytes nvr/vli486sv2g.nvr | Bin 0 -> 128 bytes nvr/win486.nvr | Bin 0 -> 128 bytes readme.txt | 775 ++++ roms/430vx/roms.txt | 1 + roms/acer386/roms.txt | 1 + roms/ami286/roms.txt | 1 + roms/ami386/roms.txt | 1 + roms/ami486/roms.txt | 1 + roms/cmdpc30/roms.txt | 1 + roms/dells200/roms.txt | 1 + roms/dtk/roms.txt | 1 + roms/endeavor/roms.txt | 1 + roms/europc/roms.txt | 1 + roms/genxt/roms.txt | 1 + roms/hot-433/roms.txt | 1 + roms/ibmat/roms.txt | 1 + roms/ibmpc/roms.txt | 1 + roms/ibmxt/roms.txt | 1 + roms/mach64gx/roms.txt | 1 + roms/mda.rom | Bin 0 -> 8192 bytes roms/megapc/roms.txt | 1 + roms/olivetti_m24/roms.txt | 1 + roms/oti067/roms.txt | 1 + roms/pc1512/roms.txt | 1 + roms/pc1640/roms.txt | 1 + roms/pc200/roms.txt | 1 + roms/pc2086/roms.txt | 1 + roms/pc3086/roms.txt | 1 + roms/revenge/roms.txt | 1 + roms/sis496/roms.txt | 1 + roms/tandy/roms.txt | 1 + roms/win486/roms.txt | 1 + src/386.c | 380 ++ src/386.h | 2 + src/386_common.h | 288 ++ src/386_dynarec.c | 1544 ++++++++ src/386_dynarec_ops.c | 57 + src/386_ops.h | 1371 +++++++ src/808x.c | 3509 ++++++++++++++++++ src/IBMPCAT-1.ico | Bin 0 -> 211418 bytes src/Makefile.am | 51 + src/Makefile.in | 2956 +++++++++++++++ src/Makefile.mingw | 51 + src/Makefile.mingw64 | 49 + src/Makefile_AMD.mingw | 50 + src/PCem.manifest | 22 + src/acer386sx.c | 33 + src/acer386sx.h | 1 + src/acerm3a.c | 29 + src/acerm3a.h | 1 + src/ali1429.c | 86 + src/ali1429.h | 1 + src/allegro-gui-configure.c | 636 ++++ src/allegro-gui-deviceconfig.c | 303 ++ src/allegro-gui-hdconf.c | 513 +++ src/allegro-gui.c | 226 ++ src/allegro-gui.h | 12 + src/allegro-joystick.c | 49 + src/allegro-keyboard.c | 49 + src/allegro-main.c | 169 + src/allegro-main.h | 19 + src/allegro-midi.c | 45 + src/allegro-mouse.c | 31 + src/allegro-video.c | 127 + src/allegro-video.h | 3 + src/amstrad.c | 83 + src/amstrad.h | 2 + src/bswap.h | 202 ++ src/cdrom-ioctl-linux.c | 724 ++++ src/cdrom-ioctl.c | 747 ++++ src/cdrom-ioctl.h | 12 + src/cdrom-iso.c | 396 ++ src/cdrom-iso.h | 14 + src/cdrom-null.c | 139 + src/cdrom-null.h | 11 + src/codegen.c | 21 + src/codegen.h | 340 ++ src/codegen_ops.c | 497 +++ src/codegen_ops.h | 37 + src/codegen_ops_arith.h | 816 +++++ src/codegen_ops_fpu.h | 601 ++++ src/codegen_ops_jump.h | 270 ++ src/codegen_ops_logic.h | 507 +++ src/codegen_ops_misc.h | 115 + src/codegen_ops_mmx.h | 277 ++ src/codegen_ops_mov.h | 506 +++ src/codegen_ops_shift.h | 114 + src/codegen_ops_stack.h | 250 ++ src/codegen_ops_x86-64.h | 4734 ++++++++++++++++++++++++ src/codegen_ops_x86.h | 3393 ++++++++++++++++++ src/codegen_ops_xchg.h | 93 + src/codegen_timing_486.c | 375 ++ src/codegen_timing_686.c | 1052 ++++++ src/codegen_timing_pentium.c | 1061 ++++++ src/codegen_timing_winchip.c | 375 ++ src/codegen_x86-64.c | 1247 +++++++ src/codegen_x86-64.h | 21 + src/codegen_x86.c | 1048 ++++++ src/codegen_x86.h | 21 + src/compaq.c | 51 + src/compaq.h | 1 + src/config.c | 400 +++ src/config.h | 16 + src/cpu.c | 2260 ++++++++++++ src/cpu.h | 146 + src/dac.c | 68 + src/device.c | 137 + src/device.h | 50 + src/disc.c | 453 +++ src/disc.h | 83 + src/disc_fdi.c | 513 +++ src/disc_fdi.h | 13 + src/disc_img.c | 702 ++++ src/disc_img.h | 13 + src/disc_sector.c | 525 +++ src/disc_sector.h | 43 + src/dma.c | 389 ++ src/dma.h | 16 + src/dosbox/dbopl.cpp | 1521 ++++++++ src/dosbox/dbopl.h | 273 ++ src/fdc.c | 1668 +++++++++ src/fdc.h | 27 + src/fdc37c665.c | 165 + src/fdc37c665.h | 1 + src/fdc37c932fr.c | 478 +++ src/fdc37c932fr.h | 1 + src/fdd.c | 325 ++ src/fdd.h | 20 + src/fdi2raw.c | 2190 ++++++++++++ src/fdi2raw.h | 34 + src/filters.h | 281 ++ src/gameport.c | 223 ++ src/gameport.h | 29 + src/headland.c | 46 + src/headland.h | 1 + src/i430fx.c | 161 + src/i430fx.h | 1 + src/i430hx.c | 128 + src/i430hx.h | 1 + src/i430lx.c | 149 + src/i430lx.h | 1 + src/i430nx.c | 147 + src/i430nx.h | 1 + src/i430vx.c | 126 + src/i430vx.h | 1 + src/i440fx.c | 130 + src/i440fx.h | 1 + src/ibm.h | 551 +++ src/ide.c | 3206 +++++++++++++++++ src/ide.h | 60 + src/intel.c | 81 + src/intel.h | 2 + src/intel_flash.c | 419 +++ src/intel_flash.h | 3 + src/io.c | 202 ++ src/io.h | 19 + src/jim.c | 79 + src/jim.h | 1 + src/joystick_standard.c | 208 ++ src/joystick_standard.h | 4 + src/joystick_sw_pad.c | 251 ++ src/joystick_sw_pad.h | 1 + src/keyboard.c | 503 +++ src/keyboard.h | 11 + src/keyboard_amstrad.c | 178 + src/keyboard_amstrad.h | 3 + src/keyboard_at.c | 648 ++++ src/keyboard_at.h | 8 + src/keyboard_olim24.c | 309 ++ src/keyboard_olim24.h | 3 + src/keyboard_pcjr.c | 208 ++ src/keyboard_pcjr.h | 3 + src/keyboard_xt.c | 184 + src/keyboard_xt.h | 4 + src/linux-time.c | 48 + src/lpt.c | 95 + src/lpt.h | 6 + src/mcr.c | 37 + src/mem.c | 2090 +++++++++++ src/mem.h | 170 + src/memregs.c | 30 + src/memregs.h | 1 + src/model.c | 618 ++++ src/model.h | 25 + src/mouse.c | 4 + src/mouse.h | 5 + src/mouse_ps2.c | 189 + src/mouse_ps2.h | 1 + src/mouse_serial.c | 72 + src/mouse_serial.h | 1 + src/ne2000.c | 2128 +++++++++++ src/ne2000.h | 2 + src/neat.c | 68 + src/neat.h | 1 + src/nethandler.c | 98 + src/nethandler.h | 15 + src/nmi.c | 15 + src/nmi.h | 5 + src/nvr.c | 489 +++ src/nvr.h | 11 + src/olivetti_m24.c | 20 + src/olivetti_m24.h | 1 + src/opti.c | 284 ++ src/pc.c | 809 +++++ src/pc.rc | 252 ++ src/pc87306.c | 295 ++ src/pc87306.h | 1 + src/pci.c | 166 + src/pci.h | 13 + src/pic.c | 423 +++ src/pic.h | 9 + src/piix.c | 570 +++ src/piix.h | 2 + src/pit.c | 627 ++++ src/pit.h | 16 + src/plat-dinput.h | 1 + src/plat-joystick.h | 65 + src/plat-keyboard.h | 19 + src/plat-midi.h | 3 + src/plat-mouse.h | 13 + src/ppi.c | 19 + src/ps1.c | 295 ++ src/ps1.h | 2 + src/resid-fp/AUTHORS | 4 + src/resid-fp/COPYING | 340 ++ src/resid-fp/ChangeLog | 136 + src/resid-fp/INSTALL | 14 + src/resid-fp/Makefile.am | 29 + src/resid-fp/Makefile.in | 557 +++ src/resid-fp/NEWS | 1 + src/resid-fp/README | 79 + src/resid-fp/README.VICE | 14 + src/resid-fp/aclocal.m4 | 850 +++++ src/resid-fp/configure | 5955 +++++++++++++++++++++++++++++++ src/resid-fp/configure.in | 166 + src/resid-fp/convolve-sse.cc | 76 + src/resid-fp/convolve.cc | 27 + src/resid-fp/envelope.cc | 254 ++ src/resid-fp/envelope.h | 174 + src/resid-fp/extfilt.cc | 94 + src/resid-fp/extfilt.h | 120 + src/resid-fp/filter.cc | 194 + src/resid-fp/filter.h | 383 ++ src/resid-fp/pot.cc | 26 + src/resid-fp/pot.h | 31 + src/resid-fp/samp2src.pl | 65 + src/resid-fp/sid.cc | 944 +++++ src/resid-fp/sid.h | 130 + src/resid-fp/siddefs-fp.h | 88 + src/resid-fp/siddefs-fp.h.in | 87 + src/resid-fp/version.cc | 21 + src/resid-fp/voice.cc | 102 + src/resid-fp/voice.h | 73 + src/resid-fp/wave.cc | 151 + src/resid-fp/wave.h | 457 +++ src/resid-fp/wave6581_PST.cc | 536 +++ src/resid-fp/wave6581_PST.dat | Bin 0 -> 4096 bytes src/resid-fp/wave6581_PS_.cc | 536 +++ src/resid-fp/wave6581_PS_.dat | Bin 0 -> 4096 bytes src/resid-fp/wave6581_P_T.cc | 536 +++ src/resid-fp/wave6581_P_T.dat | Bin 0 -> 4096 bytes src/resid-fp/wave6581__ST.cc | 536 +++ src/resid-fp/wave6581__ST.dat | Bin 0 -> 4096 bytes src/resid-fp/wave8580_PST.cc | 536 +++ src/resid-fp/wave8580_PST.dat | Bin 0 -> 4096 bytes src/resid-fp/wave8580_PS_.cc | 536 +++ src/resid-fp/wave8580_PS_.dat | Bin 0 -> 4096 bytes src/resid-fp/wave8580_P_T.cc | 536 +++ src/resid-fp/wave8580_P_T.dat | Bin 0 -> 4096 bytes src/resid-fp/wave8580__ST.cc | 536 +++ src/resid-fp/wave8580__ST.dat | Bin 0 -> 4096 bytes src/resources.h | 139 + src/rom.c | 125 + src/rom.h | 12 + src/scat.c | 495 +++ src/scat.h | 22 + src/scsi_cmds.h | 90 + src/serial.c | 292 ++ src/serial.h | 28 + src/sio.c | 75 + src/sio.h | 1 + src/sis496.c | 127 + src/sis496.h | 1 + src/sis50x.c | 288 ++ src/sis50x.h | 3 + src/sis85c471.c | 228 ++ src/sis85c471.h | 1 + src/slirp/COPYRIGHT.txt | 61 + src/slirp/Makefile | 26 + src/slirp/VERSION.txt | 1 + src/slirp/bootp.c | 242 ++ src/slirp/bootp.h | 121 + src/slirp/cksum.c | 137 + src/slirp/config-host.h | 9 + src/slirp/config.h | 9 + src/slirp/ctl.h | 7 + src/slirp/debug.c | 440 +++ src/slirp/debug.h | 50 + src/slirp/icmp_var.h | 65 + src/slirp/if.c | 322 ++ src/slirp/if.h | 50 + src/slirp/ip.h | 341 ++ src/slirp/ip_icmp.c | 371 ++ src/slirp/ip_icmp.h | 168 + src/slirp/ip_input.c | 693 ++++ src/slirp/ip_output.c | 202 ++ src/slirp/libslirp.h | 41 + src/slirp/main.h | 54 + src/slirp/mbuf.c | 248 ++ src/slirp/mbuf.h | 143 + src/slirp/misc.c | 970 +++++ src/slirp/misc.h | 87 + src/slirp/queue.c | 116 + src/slirp/queue.h | 99 + src/slirp/sbuf.c | 202 ++ src/slirp/sbuf.h | 31 + src/slirp/slirp.c | 682 ++++ src/slirp/slirp.h | 415 +++ src/slirp/slirp_config.h | 135 + src/slirp/socket.c | 731 ++++ src/slirp/socket.h | 104 + src/slirp/tcp.h | 181 + src/slirp/tcp_input.c | 1722 +++++++++ src/slirp/tcp_output.c | 601 ++++ src/slirp/tcp_subr.c | 1324 +++++++ src/slirp/tcp_timer.c | 322 ++ src/slirp/tcp_timer.h | 138 + src/slirp/tcp_var.h | 248 ++ src/slirp/tcpip.h | 70 + src/slirp/tftp.c | 332 ++ src/slirp/tftp.h | 40 + src/slirp/udp.c | 676 ++++ src/slirp/udp.h | 114 + src/sound.c | 230 ++ src/sound.h | 20 + src/sound_ad1848.c | 219 ++ src/sound_ad1848.h | 35 + src/sound_adlib.c | 56 + src/sound_adlib.h | 1 + src/sound_adlibgold.c | 863 +++++ src/sound_adlibgold.h | 1 + src/sound_cms.c | 183 + src/sound_cms.h | 1 + src/sound_dbopl.cc | 141 + src/sound_dbopl.h | 12 + src/sound_emu8k.c | 754 ++++ src/sound_emu8k.h | 90 + src/sound_gus.c | 1138 ++++++ src/sound_gus.h | 1 + src/sound_mameopl.c | 200 ++ src/sound_mpu401_uart.c | 57 + src/sound_mpu401_uart.h | 9 + src/sound_opl.c | 176 + src/sound_opl.h | 30 + src/sound_pas16.c | 763 ++++ src/sound_pas16.h | 1 + src/sound_ps1.c | 174 + src/sound_ps1.h | 1 + src/sound_pssj.c | 214 ++ src/sound_pssj.h | 1 + src/sound_resid.cc | 108 + src/sound_resid.h | 12 + src/sound_sb.c | 840 +++++ src/sound_sb.h | 7 + src/sound_sb_dsp.c | 1013 ++++++ src/sound_sb_dsp.h | 78 + src/sound_sn76489.c | 250 ++ src/sound_sn76489.h | 33 + src/sound_speaker.c | 59 + src/sound_speaker.h | 8 + src/sound_ssi2001.c | 87 + src/sound_ssi2001.h | 1 + src/sound_wss.c | 125 + src/sound_wss.h | 1 + src/sound_ym7128.c | 142 + src/sound_ym7128.h | 25 + src/soundopenal.c | 257 ++ src/tandy_eeprom.c | 178 + src/tandy_eeprom.h | 2 + src/tandy_rom.c | 94 + src/tandy_rom.h | 1 + src/thread-pthread.c | 89 + src/thread.h | 12 + src/timer.c | 118 + src/timer.h | 58 + src/um8669f.c | 137 + src/um8669f.h | 1 + src/um8881f.c | 70 + src/um8881f.h | 1 + src/vid_ati18800.c | 199 ++ src/vid_ati18800.h | 1 + src/vid_ati28800.c | 279 ++ src/vid_ati28800.h | 2 + src/vid_ati68860_ramdac.c | 176 + src/vid_ati68860_ramdac.h | 17 + src/vid_ati_eeprom.c | 220 ++ src/vid_ati_eeprom.h | 16 + src/vid_ati_mach64.c | 2731 ++++++++++++++ src/vid_ati_mach64.h | 1 + src/vid_cga.c | 524 +++ src/vid_cga.h | 41 + src/vid_cga_comp.c | 356 ++ src/vid_cga_comp.h | 8 + src/vid_cl5429.c | 915 +++++ src/vid_cl5429.h | 1 + src/vid_ega.c | 1141 ++++++ src/vid_ega.h | 80 + src/vid_et4000.c | 211 ++ src/vid_et4000.h | 1 + src/vid_et4000w32.c | 1451 ++++++++ src/vid_et4000w32.h | 2 + src/vid_et4000w32i.c | 407 +++ src/vid_hercules.c | 371 ++ src/vid_hercules.h | 1 + src/vid_icd2061.c | 66 + src/vid_icd2061.h | 14 + src/vid_ics2595.c | 55 + src/vid_ics2595.h | 12 + src/vid_incolor.c | 1061 ++++++ src/vid_incolor.h | 1 + src/vid_mda.c | 328 ++ src/vid_mda.h | 1 + src/vid_olivetti_m24.c | 490 +++ src/vid_olivetti_m24.h | 1 + src/vid_oti067.c | 343 ++ src/vid_oti067.h | 3 + src/vid_paradise.c | 463 +++ src/vid_paradise.h | 5 + src/vid_pc1512.c | 494 +++ src/vid_pc1512.h | 1 + src/vid_pc1640.c | 164 + src/vid_pc1640.h | 1 + src/vid_pc200.c | 146 + src/vid_pc200.h | 1 + src/vid_pcjr.c | 647 ++++ src/vid_pcjr.h | 1 + src/vid_ps1_svga.c | 189 + src/vid_ps1_svga.h | 1 + src/vid_s3.c | 2563 +++++++++++++ src/vid_s3.h | 5 + src/vid_s3_virge.c | 4071 +++++++++++++++++++++ src/vid_s3_virge.h | 2 + src/vid_sdac_ramdac.c | 169 + src/vid_sdac_ramdac.h | 14 + src/vid_stg_ramdac.c | 137 + src/vid_stg_ramdac.h | 11 + src/vid_svga.c | 1634 +++++++++ src/vid_svga.h | 154 + src/vid_svga_render.c | 744 ++++ src/vid_svga_render.h | 33 + src/vid_tandy.c | 726 ++++ src/vid_tandy.h | 1 + src/vid_tandysl.c | 733 ++++ src/vid_tandysl.h | 1 + src/vid_tgui9440.c | 1333 +++++++ src/vid_tgui9440.h | 1 + src/vid_tkd8001_ramdac.c | 65 + src/vid_tkd8001_ramdac.h | 8 + src/vid_tvga.c | 389 ++ src/vid_tvga.h | 1 + src/vid_unk_ramdac.c | 64 + src/vid_unk_ramdac.h | 8 + src/vid_vga.c | 181 + src/vid_vga.h | 2 + src/vid_voodoo.c | 4565 +++++++++++++++++++++++ src/vid_voodoo.h | 1 + src/vid_voodoo_codegen_x86-64.h | 3720 +++++++++++++++++++ src/vid_voodoo_codegen_x86.h | 3725 +++++++++++++++++++ src/vid_voodoo_dither.h | 5136 ++++++++++++++++++++++++++ src/video.c | 495 +++ src/video.h | 105 + src/w83877f.c | 520 +++ src/w83877f.h | 1 + src/wd76c10.c | 99 + src/wd76c10.h | 1 + src/win-config.c | 694 ++++ src/win-d3d-fs.cc | 506 +++ src/win-d3d-fs.h | 10 + src/win-d3d.cc | 401 +++ src/win-d3d.h | 10 + src/win-ddraw-fs.cc | 336 ++ src/win-ddraw-fs.h | 8 + src/win-ddraw-screenshot.cc | 169 + src/win-ddraw-screenshot.h | 1 + src/win-ddraw.cc | 315 ++ src/win-ddraw.h | 9 + src/win-deviceconfig.c | 354 ++ src/win-hdconf.c | 809 +++++ src/win-joystick.cc | 255 ++ src/win-joystickconfig.c | 407 +++ src/win-keyboard.cc | 57 + src/win-midi.c | 113 + src/win-mouse.cc | 70 + src/win-status.c | 103 + src/win-time.c | 48 + src/win-video.c | 51 + src/win.c | 1487 ++++++++ src/win.h | 35 + src/x86.h | 108 + src/x86_flags.h | 507 +++ src/x86_ops.h | 138 + src/x86_ops_arith.h | 647 ++++ src/x86_ops_atomic.h | 278 ++ src/x86_ops_bcd.h | 107 + src/x86_ops_bit.h | 297 ++ src/x86_ops_bitscan.h | 117 + src/x86_ops_call.h | 348 ++ src/x86_ops_flag.h | 190 + src/x86_ops_fpu.h | 82 + src/x86_ops_i686.h | 651 ++++ src/x86_ops_inc_dec.h | 86 + src/x86_ops_int - Cópia.h | 77 + src/x86_ops_int.h | 77 + src/x86_ops_io - Cópia.h | 112 + src/x86_ops_io.h | 112 + src/x86_ops_jump.h | 305 ++ src/x86_ops_misc.h | 805 +++++ src/x86_ops_mmx.h | 48 + src/x86_ops_mmx_arith.h | 625 ++++ src/x86_ops_mmx_cmp.h | 205 ++ src/x86_ops_mmx_logic.h | 91 + src/x86_ops_mmx_mov.h | 161 + src/x86_ops_mmx_pack.h | 324 ++ src/x86_ops_mmx_shift.h | 452 +++ src/x86_ops_mov.h | 655 ++++ src/x86_ops_mov_ctrl.h | 268 ++ src/x86_ops_mov_seg.h | 394 ++ src/x86_ops_movx.h | 167 + src/x86_ops_msr.h | 30 + src/x86_ops_mul.h | 222 ++ src/x86_ops_pmode.h | 408 +++ src/x86_ops_prefix.h | 80 + src/x86_ops_rep.h | 9 + src/x86_ops_ret.h | 194 + src/x86_ops_set.h | 33 + src/x86_ops_shift.h | 571 +++ src/x86_ops_stack.h | 476 +++ src/x86_ops_string.h | 435 +++ src/x86_ops_xchg.h | 195 + src/x86seg.c | 2597 ++++++++++++++ src/x86seg.h | 1 + src/x87.c | 90 + src/x87.h | 32 + src/x87_ops.h | 1127 ++++++ src/x87_ops_arith.h | 428 +++ src/x87_ops_loadstore.h | 470 +++ src/x87_ops_misc.h | 828 +++++ src/xtide.c | 58 + src/xtide.h | 1 + 610 files changed, 184352 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 README create mode 100644 Readme-LINUX.txt create mode 100644 aclocal.m4 create mode 100644 compile create mode 100644 config.guess create mode 100644 config.sub create mode 100644 configure create mode 100644 configure.ac create mode 100644 depcomp create mode 100644 install-sh create mode 100644 missing create mode 100644 nvr/430vx.nvr create mode 100644 nvr/440fx.nvr create mode 100644 nvr/586mc1.nvr create mode 100644 nvr/acer386.nvr create mode 100644 nvr/acerm3a.nvr create mode 100644 nvr/acerv35n.nvr create mode 100644 nvr/adgold.bin create mode 100644 nvr/ami286.nvr create mode 100644 nvr/ami386.nvr create mode 100644 nvr/ami486.nvr create mode 100644 nvr/at.nvr create mode 100644 nvr/cmdpc30.nvr create mode 100644 nvr/dell200.nvr create mode 100644 nvr/deskpro386.nvr create mode 100644 nvr/dtk386.nvr create mode 100644 nvr/dtk486.nvr create mode 100644 nvr/endeavor.nvr create mode 100644 nvr/europc.nvr create mode 100644 nvr/hot-433.nvr create mode 100644 nvr/ibmps1_2011.nvr create mode 100644 nvr/ibmps1_2121.nvr create mode 100644 nvr/kn97.nvr create mode 100644 nvr/mb500n.nvr create mode 100644 nvr/megapc.nvr create mode 100644 nvr/p54tp4xe.nvr create mode 100644 nvr/p55t2p4.nvr create mode 100644 nvr/p55tp4n.nvr create mode 100644 nvr/p55tp4xe.nvr create mode 100644 nvr/p55tvp4.nvr create mode 100644 nvr/p55va.nvr create mode 100644 nvr/p5sp4.nvr create mode 100644 nvr/pc1512.nvr create mode 100644 nvr/pc1640.nvr create mode 100644 nvr/pc200.nvr create mode 100644 nvr/pc2086.nvr create mode 100644 nvr/pc3086.nvr create mode 100644 nvr/plato.nvr create mode 100644 nvr/px386.nvr create mode 100644 nvr/r418.nvr create mode 100644 nvr/revenge.nvr create mode 100644 nvr/sis496.nvr create mode 100644 nvr/tandy1000hx.bin create mode 100644 nvr/tandy1000sl2.bin create mode 100644 nvr/vli486sv2g.nvr create mode 100644 nvr/win486.nvr create mode 100644 readme.txt create mode 100644 roms/430vx/roms.txt create mode 100644 roms/acer386/roms.txt create mode 100644 roms/ami286/roms.txt create mode 100644 roms/ami386/roms.txt create mode 100644 roms/ami486/roms.txt create mode 100644 roms/cmdpc30/roms.txt create mode 100644 roms/dells200/roms.txt create mode 100644 roms/dtk/roms.txt create mode 100644 roms/endeavor/roms.txt create mode 100644 roms/europc/roms.txt create mode 100644 roms/genxt/roms.txt create mode 100644 roms/hot-433/roms.txt create mode 100644 roms/ibmat/roms.txt create mode 100644 roms/ibmpc/roms.txt create mode 100644 roms/ibmxt/roms.txt create mode 100644 roms/mach64gx/roms.txt create mode 100644 roms/mda.rom create mode 100644 roms/megapc/roms.txt create mode 100644 roms/olivetti_m24/roms.txt create mode 100644 roms/oti067/roms.txt create mode 100644 roms/pc1512/roms.txt create mode 100644 roms/pc1640/roms.txt create mode 100644 roms/pc200/roms.txt create mode 100644 roms/pc2086/roms.txt create mode 100644 roms/pc3086/roms.txt create mode 100644 roms/revenge/roms.txt create mode 100644 roms/sis496/roms.txt create mode 100644 roms/tandy/roms.txt create mode 100644 roms/win486/roms.txt create mode 100644 src/386.c create mode 100644 src/386.h create mode 100644 src/386_common.h create mode 100644 src/386_dynarec.c create mode 100644 src/386_dynarec_ops.c create mode 100644 src/386_ops.h create mode 100644 src/808x.c create mode 100644 src/IBMPCAT-1.ico create mode 100644 src/Makefile.am create mode 100644 src/Makefile.in create mode 100644 src/Makefile.mingw create mode 100644 src/Makefile.mingw64 create mode 100644 src/Makefile_AMD.mingw create mode 100644 src/PCem.manifest create mode 100644 src/acer386sx.c create mode 100644 src/acer386sx.h create mode 100644 src/acerm3a.c create mode 100644 src/acerm3a.h create mode 100644 src/ali1429.c create mode 100644 src/ali1429.h create mode 100644 src/allegro-gui-configure.c create mode 100644 src/allegro-gui-deviceconfig.c create mode 100644 src/allegro-gui-hdconf.c create mode 100644 src/allegro-gui.c create mode 100644 src/allegro-gui.h create mode 100644 src/allegro-joystick.c create mode 100644 src/allegro-keyboard.c create mode 100644 src/allegro-main.c create mode 100644 src/allegro-main.h create mode 100644 src/allegro-midi.c create mode 100644 src/allegro-mouse.c create mode 100644 src/allegro-video.c create mode 100644 src/allegro-video.h create mode 100644 src/amstrad.c create mode 100644 src/amstrad.h create mode 100644 src/bswap.h create mode 100644 src/cdrom-ioctl-linux.c create mode 100644 src/cdrom-ioctl.c create mode 100644 src/cdrom-ioctl.h create mode 100644 src/cdrom-iso.c create mode 100644 src/cdrom-iso.h create mode 100644 src/cdrom-null.c create mode 100644 src/cdrom-null.h create mode 100644 src/codegen.c create mode 100644 src/codegen.h create mode 100644 src/codegen_ops.c create mode 100644 src/codegen_ops.h create mode 100644 src/codegen_ops_arith.h create mode 100644 src/codegen_ops_fpu.h create mode 100644 src/codegen_ops_jump.h create mode 100644 src/codegen_ops_logic.h create mode 100644 src/codegen_ops_misc.h create mode 100644 src/codegen_ops_mmx.h create mode 100644 src/codegen_ops_mov.h create mode 100644 src/codegen_ops_shift.h create mode 100644 src/codegen_ops_stack.h create mode 100644 src/codegen_ops_x86-64.h create mode 100644 src/codegen_ops_x86.h create mode 100644 src/codegen_ops_xchg.h create mode 100644 src/codegen_timing_486.c create mode 100644 src/codegen_timing_686.c create mode 100644 src/codegen_timing_pentium.c create mode 100644 src/codegen_timing_winchip.c create mode 100644 src/codegen_x86-64.c create mode 100644 src/codegen_x86-64.h create mode 100644 src/codegen_x86.c create mode 100644 src/codegen_x86.h create mode 100644 src/compaq.c create mode 100644 src/compaq.h create mode 100644 src/config.c create mode 100644 src/config.h create mode 100644 src/cpu.c create mode 100644 src/cpu.h create mode 100644 src/dac.c create mode 100644 src/device.c create mode 100644 src/device.h create mode 100644 src/disc.c create mode 100644 src/disc.h create mode 100644 src/disc_fdi.c create mode 100644 src/disc_fdi.h create mode 100644 src/disc_img.c create mode 100644 src/disc_img.h create mode 100644 src/disc_sector.c create mode 100644 src/disc_sector.h create mode 100644 src/dma.c create mode 100644 src/dma.h create mode 100644 src/dosbox/dbopl.cpp create mode 100644 src/dosbox/dbopl.h create mode 100644 src/fdc.c create mode 100644 src/fdc.h create mode 100644 src/fdc37c665.c create mode 100644 src/fdc37c665.h create mode 100644 src/fdc37c932fr.c create mode 100644 src/fdc37c932fr.h create mode 100644 src/fdd.c create mode 100644 src/fdd.h create mode 100644 src/fdi2raw.c create mode 100644 src/fdi2raw.h create mode 100644 src/filters.h create mode 100644 src/gameport.c create mode 100644 src/gameport.h create mode 100644 src/headland.c create mode 100644 src/headland.h create mode 100644 src/i430fx.c create mode 100644 src/i430fx.h create mode 100644 src/i430hx.c create mode 100644 src/i430hx.h create mode 100644 src/i430lx.c create mode 100644 src/i430lx.h create mode 100644 src/i430nx.c create mode 100644 src/i430nx.h create mode 100644 src/i430vx.c create mode 100644 src/i430vx.h create mode 100644 src/i440fx.c create mode 100644 src/i440fx.h create mode 100644 src/ibm.h create mode 100644 src/ide.c create mode 100644 src/ide.h create mode 100644 src/intel.c create mode 100644 src/intel.h create mode 100644 src/intel_flash.c create mode 100644 src/intel_flash.h create mode 100644 src/io.c create mode 100644 src/io.h create mode 100644 src/jim.c create mode 100644 src/jim.h create mode 100644 src/joystick_standard.c create mode 100644 src/joystick_standard.h create mode 100644 src/joystick_sw_pad.c create mode 100644 src/joystick_sw_pad.h create mode 100644 src/keyboard.c create mode 100644 src/keyboard.h create mode 100644 src/keyboard_amstrad.c create mode 100644 src/keyboard_amstrad.h create mode 100644 src/keyboard_at.c create mode 100644 src/keyboard_at.h create mode 100644 src/keyboard_olim24.c create mode 100644 src/keyboard_olim24.h create mode 100644 src/keyboard_pcjr.c create mode 100644 src/keyboard_pcjr.h create mode 100644 src/keyboard_xt.c create mode 100644 src/keyboard_xt.h create mode 100644 src/linux-time.c create mode 100644 src/lpt.c create mode 100644 src/lpt.h create mode 100644 src/mcr.c create mode 100644 src/mem.c create mode 100644 src/mem.h create mode 100644 src/memregs.c create mode 100644 src/memregs.h create mode 100644 src/model.c create mode 100644 src/model.h create mode 100644 src/mouse.c create mode 100644 src/mouse.h create mode 100644 src/mouse_ps2.c create mode 100644 src/mouse_ps2.h create mode 100644 src/mouse_serial.c create mode 100644 src/mouse_serial.h create mode 100644 src/ne2000.c create mode 100644 src/ne2000.h create mode 100644 src/neat.c create mode 100644 src/neat.h create mode 100644 src/nethandler.c create mode 100644 src/nethandler.h create mode 100644 src/nmi.c create mode 100644 src/nmi.h create mode 100644 src/nvr.c create mode 100644 src/nvr.h create mode 100644 src/olivetti_m24.c create mode 100644 src/olivetti_m24.h create mode 100644 src/opti.c create mode 100644 src/pc.c create mode 100644 src/pc.rc create mode 100644 src/pc87306.c create mode 100644 src/pc87306.h create mode 100644 src/pci.c create mode 100644 src/pci.h create mode 100644 src/pic.c create mode 100644 src/pic.h create mode 100644 src/piix.c create mode 100644 src/piix.h create mode 100644 src/pit.c create mode 100644 src/pit.h create mode 100644 src/plat-dinput.h create mode 100644 src/plat-joystick.h create mode 100644 src/plat-keyboard.h create mode 100644 src/plat-midi.h create mode 100644 src/plat-mouse.h create mode 100644 src/ppi.c create mode 100644 src/ps1.c create mode 100644 src/ps1.h create mode 100644 src/resid-fp/AUTHORS create mode 100644 src/resid-fp/COPYING create mode 100644 src/resid-fp/ChangeLog create mode 100644 src/resid-fp/INSTALL create mode 100644 src/resid-fp/Makefile.am create mode 100644 src/resid-fp/Makefile.in create mode 100644 src/resid-fp/NEWS create mode 100644 src/resid-fp/README create mode 100644 src/resid-fp/README.VICE create mode 100644 src/resid-fp/aclocal.m4 create mode 100644 src/resid-fp/configure create mode 100644 src/resid-fp/configure.in create mode 100644 src/resid-fp/convolve-sse.cc create mode 100644 src/resid-fp/convolve.cc create mode 100644 src/resid-fp/envelope.cc create mode 100644 src/resid-fp/envelope.h create mode 100644 src/resid-fp/extfilt.cc create mode 100644 src/resid-fp/extfilt.h create mode 100644 src/resid-fp/filter.cc create mode 100644 src/resid-fp/filter.h create mode 100644 src/resid-fp/pot.cc create mode 100644 src/resid-fp/pot.h create mode 100644 src/resid-fp/samp2src.pl create mode 100644 src/resid-fp/sid.cc create mode 100644 src/resid-fp/sid.h create mode 100644 src/resid-fp/siddefs-fp.h create mode 100644 src/resid-fp/siddefs-fp.h.in create mode 100644 src/resid-fp/version.cc create mode 100644 src/resid-fp/voice.cc create mode 100644 src/resid-fp/voice.h create mode 100644 src/resid-fp/wave.cc create mode 100644 src/resid-fp/wave.h create mode 100644 src/resid-fp/wave6581_PST.cc create mode 100644 src/resid-fp/wave6581_PST.dat create mode 100644 src/resid-fp/wave6581_PS_.cc create mode 100644 src/resid-fp/wave6581_PS_.dat create mode 100644 src/resid-fp/wave6581_P_T.cc create mode 100644 src/resid-fp/wave6581_P_T.dat create mode 100644 src/resid-fp/wave6581__ST.cc create mode 100644 src/resid-fp/wave6581__ST.dat create mode 100644 src/resid-fp/wave8580_PST.cc create mode 100644 src/resid-fp/wave8580_PST.dat create mode 100644 src/resid-fp/wave8580_PS_.cc create mode 100644 src/resid-fp/wave8580_PS_.dat create mode 100644 src/resid-fp/wave8580_P_T.cc create mode 100644 src/resid-fp/wave8580_P_T.dat create mode 100644 src/resid-fp/wave8580__ST.cc create mode 100644 src/resid-fp/wave8580__ST.dat create mode 100644 src/resources.h create mode 100644 src/rom.c create mode 100644 src/rom.h create mode 100644 src/scat.c create mode 100644 src/scat.h create mode 100644 src/scsi_cmds.h create mode 100644 src/serial.c create mode 100644 src/serial.h create mode 100644 src/sio.c create mode 100644 src/sio.h create mode 100644 src/sis496.c create mode 100644 src/sis496.h create mode 100644 src/sis50x.c create mode 100644 src/sis50x.h create mode 100644 src/sis85c471.c create mode 100644 src/sis85c471.h create mode 100644 src/slirp/COPYRIGHT.txt create mode 100644 src/slirp/Makefile create mode 100644 src/slirp/VERSION.txt create mode 100644 src/slirp/bootp.c create mode 100644 src/slirp/bootp.h create mode 100644 src/slirp/cksum.c create mode 100644 src/slirp/config-host.h create mode 100644 src/slirp/config.h create mode 100644 src/slirp/ctl.h create mode 100644 src/slirp/debug.c create mode 100644 src/slirp/debug.h create mode 100644 src/slirp/icmp_var.h create mode 100644 src/slirp/if.c create mode 100644 src/slirp/if.h create mode 100644 src/slirp/ip.h create mode 100644 src/slirp/ip_icmp.c create mode 100644 src/slirp/ip_icmp.h create mode 100644 src/slirp/ip_input.c create mode 100644 src/slirp/ip_output.c create mode 100644 src/slirp/libslirp.h create mode 100644 src/slirp/main.h create mode 100644 src/slirp/mbuf.c create mode 100644 src/slirp/mbuf.h create mode 100644 src/slirp/misc.c create mode 100644 src/slirp/misc.h create mode 100644 src/slirp/queue.c create mode 100644 src/slirp/queue.h create mode 100644 src/slirp/sbuf.c create mode 100644 src/slirp/sbuf.h create mode 100644 src/slirp/slirp.c create mode 100644 src/slirp/slirp.h create mode 100644 src/slirp/slirp_config.h create mode 100644 src/slirp/socket.c create mode 100644 src/slirp/socket.h create mode 100644 src/slirp/tcp.h create mode 100644 src/slirp/tcp_input.c create mode 100644 src/slirp/tcp_output.c create mode 100644 src/slirp/tcp_subr.c create mode 100644 src/slirp/tcp_timer.c create mode 100644 src/slirp/tcp_timer.h create mode 100644 src/slirp/tcp_var.h create mode 100644 src/slirp/tcpip.h create mode 100644 src/slirp/tftp.c create mode 100644 src/slirp/tftp.h create mode 100644 src/slirp/udp.c create mode 100644 src/slirp/udp.h create mode 100644 src/sound.c create mode 100644 src/sound.h create mode 100644 src/sound_ad1848.c create mode 100644 src/sound_ad1848.h create mode 100644 src/sound_adlib.c create mode 100644 src/sound_adlib.h create mode 100644 src/sound_adlibgold.c create mode 100644 src/sound_adlibgold.h create mode 100644 src/sound_cms.c create mode 100644 src/sound_cms.h create mode 100644 src/sound_dbopl.cc create mode 100644 src/sound_dbopl.h create mode 100644 src/sound_emu8k.c create mode 100644 src/sound_emu8k.h create mode 100644 src/sound_gus.c create mode 100644 src/sound_gus.h create mode 100644 src/sound_mameopl.c create mode 100644 src/sound_mpu401_uart.c create mode 100644 src/sound_mpu401_uart.h create mode 100644 src/sound_opl.c create mode 100644 src/sound_opl.h create mode 100644 src/sound_pas16.c create mode 100644 src/sound_pas16.h create mode 100644 src/sound_ps1.c create mode 100644 src/sound_ps1.h create mode 100644 src/sound_pssj.c create mode 100644 src/sound_pssj.h create mode 100644 src/sound_resid.cc create mode 100644 src/sound_resid.h create mode 100644 src/sound_sb.c create mode 100644 src/sound_sb.h create mode 100644 src/sound_sb_dsp.c create mode 100644 src/sound_sb_dsp.h create mode 100644 src/sound_sn76489.c create mode 100644 src/sound_sn76489.h create mode 100644 src/sound_speaker.c create mode 100644 src/sound_speaker.h create mode 100644 src/sound_ssi2001.c create mode 100644 src/sound_ssi2001.h create mode 100644 src/sound_wss.c create mode 100644 src/sound_wss.h create mode 100644 src/sound_ym7128.c create mode 100644 src/sound_ym7128.h create mode 100644 src/soundopenal.c create mode 100644 src/tandy_eeprom.c create mode 100644 src/tandy_eeprom.h create mode 100644 src/tandy_rom.c create mode 100644 src/tandy_rom.h create mode 100644 src/thread-pthread.c create mode 100644 src/thread.h create mode 100644 src/timer.c create mode 100644 src/timer.h create mode 100644 src/um8669f.c create mode 100644 src/um8669f.h create mode 100644 src/um8881f.c create mode 100644 src/um8881f.h create mode 100644 src/vid_ati18800.c create mode 100644 src/vid_ati18800.h create mode 100644 src/vid_ati28800.c create mode 100644 src/vid_ati28800.h create mode 100644 src/vid_ati68860_ramdac.c create mode 100644 src/vid_ati68860_ramdac.h create mode 100644 src/vid_ati_eeprom.c create mode 100644 src/vid_ati_eeprom.h create mode 100644 src/vid_ati_mach64.c create mode 100644 src/vid_ati_mach64.h create mode 100644 src/vid_cga.c create mode 100644 src/vid_cga.h create mode 100644 src/vid_cga_comp.c create mode 100644 src/vid_cga_comp.h create mode 100644 src/vid_cl5429.c create mode 100644 src/vid_cl5429.h create mode 100644 src/vid_ega.c create mode 100644 src/vid_ega.h create mode 100644 src/vid_et4000.c create mode 100644 src/vid_et4000.h create mode 100644 src/vid_et4000w32.c create mode 100644 src/vid_et4000w32.h create mode 100644 src/vid_et4000w32i.c create mode 100644 src/vid_hercules.c create mode 100644 src/vid_hercules.h create mode 100644 src/vid_icd2061.c create mode 100644 src/vid_icd2061.h create mode 100644 src/vid_ics2595.c create mode 100644 src/vid_ics2595.h create mode 100644 src/vid_incolor.c create mode 100644 src/vid_incolor.h create mode 100644 src/vid_mda.c create mode 100644 src/vid_mda.h create mode 100644 src/vid_olivetti_m24.c create mode 100644 src/vid_olivetti_m24.h create mode 100644 src/vid_oti067.c create mode 100644 src/vid_oti067.h create mode 100644 src/vid_paradise.c create mode 100644 src/vid_paradise.h create mode 100644 src/vid_pc1512.c create mode 100644 src/vid_pc1512.h create mode 100644 src/vid_pc1640.c create mode 100644 src/vid_pc1640.h create mode 100644 src/vid_pc200.c create mode 100644 src/vid_pc200.h create mode 100644 src/vid_pcjr.c create mode 100644 src/vid_pcjr.h create mode 100644 src/vid_ps1_svga.c create mode 100644 src/vid_ps1_svga.h create mode 100644 src/vid_s3.c create mode 100644 src/vid_s3.h create mode 100644 src/vid_s3_virge.c create mode 100644 src/vid_s3_virge.h create mode 100644 src/vid_sdac_ramdac.c create mode 100644 src/vid_sdac_ramdac.h create mode 100644 src/vid_stg_ramdac.c create mode 100644 src/vid_stg_ramdac.h create mode 100644 src/vid_svga.c create mode 100644 src/vid_svga.h create mode 100644 src/vid_svga_render.c create mode 100644 src/vid_svga_render.h create mode 100644 src/vid_tandy.c create mode 100644 src/vid_tandy.h create mode 100644 src/vid_tandysl.c create mode 100644 src/vid_tandysl.h create mode 100644 src/vid_tgui9440.c create mode 100644 src/vid_tgui9440.h create mode 100644 src/vid_tkd8001_ramdac.c create mode 100644 src/vid_tkd8001_ramdac.h create mode 100644 src/vid_tvga.c create mode 100644 src/vid_tvga.h create mode 100644 src/vid_unk_ramdac.c create mode 100644 src/vid_unk_ramdac.h create mode 100644 src/vid_vga.c create mode 100644 src/vid_vga.h create mode 100644 src/vid_voodoo.c create mode 100644 src/vid_voodoo.h create mode 100644 src/vid_voodoo_codegen_x86-64.h create mode 100644 src/vid_voodoo_codegen_x86.h create mode 100644 src/vid_voodoo_dither.h create mode 100644 src/video.c create mode 100644 src/video.h create mode 100644 src/w83877f.c create mode 100644 src/w83877f.h create mode 100644 src/wd76c10.c create mode 100644 src/wd76c10.h create mode 100644 src/win-config.c create mode 100644 src/win-d3d-fs.cc create mode 100644 src/win-d3d-fs.h create mode 100644 src/win-d3d.cc create mode 100644 src/win-d3d.h create mode 100644 src/win-ddraw-fs.cc create mode 100644 src/win-ddraw-fs.h create mode 100644 src/win-ddraw-screenshot.cc create mode 100644 src/win-ddraw-screenshot.h create mode 100644 src/win-ddraw.cc create mode 100644 src/win-ddraw.h create mode 100644 src/win-deviceconfig.c create mode 100644 src/win-hdconf.c create mode 100644 src/win-joystick.cc create mode 100644 src/win-joystickconfig.c create mode 100644 src/win-keyboard.cc create mode 100644 src/win-midi.c create mode 100644 src/win-mouse.cc create mode 100644 src/win-status.c create mode 100644 src/win-time.c create mode 100644 src/win-video.c create mode 100644 src/win.c create mode 100644 src/win.h create mode 100644 src/x86.h create mode 100644 src/x86_flags.h create mode 100644 src/x86_ops.h create mode 100644 src/x86_ops_arith.h create mode 100644 src/x86_ops_atomic.h create mode 100644 src/x86_ops_bcd.h create mode 100644 src/x86_ops_bit.h create mode 100644 src/x86_ops_bitscan.h create mode 100644 src/x86_ops_call.h create mode 100644 src/x86_ops_flag.h create mode 100644 src/x86_ops_fpu.h create mode 100644 src/x86_ops_i686.h create mode 100644 src/x86_ops_inc_dec.h create mode 100644 src/x86_ops_int - Cópia.h create mode 100644 src/x86_ops_int.h create mode 100644 src/x86_ops_io - Cópia.h create mode 100644 src/x86_ops_io.h create mode 100644 src/x86_ops_jump.h create mode 100644 src/x86_ops_misc.h create mode 100644 src/x86_ops_mmx.h create mode 100644 src/x86_ops_mmx_arith.h create mode 100644 src/x86_ops_mmx_cmp.h create mode 100644 src/x86_ops_mmx_logic.h create mode 100644 src/x86_ops_mmx_mov.h create mode 100644 src/x86_ops_mmx_pack.h create mode 100644 src/x86_ops_mmx_shift.h create mode 100644 src/x86_ops_mov.h create mode 100644 src/x86_ops_mov_ctrl.h create mode 100644 src/x86_ops_mov_seg.h create mode 100644 src/x86_ops_movx.h create mode 100644 src/x86_ops_msr.h create mode 100644 src/x86_ops_mul.h create mode 100644 src/x86_ops_pmode.h create mode 100644 src/x86_ops_prefix.h create mode 100644 src/x86_ops_rep.h create mode 100644 src/x86_ops_ret.h create mode 100644 src/x86_ops_set.h create mode 100644 src/x86_ops_shift.h create mode 100644 src/x86_ops_stack.h create mode 100644 src/x86_ops_string.h create mode 100644 src/x86_ops_xchg.h create mode 100644 src/x86seg.c create mode 100644 src/x86seg.h create mode 100644 src/x87.c create mode 100644 src/x87.h create mode 100644 src/x87_ops.h create mode 100644 src/x87_ops_arith.h create mode 100644 src/x87_ops_loadstore.h create mode 100644 src/x87_ops_misc.h create mode 100644 src/xtide.c create mode 100644 src/xtide.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..e69de29bb diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..a43ea2126 --- /dev/null +++ b/COPYING @@ -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 + + Appendix: 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. + + + Copyright (C) 19yy + + 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. + + , 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/ChangeLog b/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..cbd1c80d2 --- /dev/null +++ b/INSTALL @@ -0,0 +1 @@ +/usr/share/automake-1.11/INSTALL \ No newline at end of file diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..f26892443 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = src + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 000000000..d680f1741 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,670 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/configure AUTHORS COPYING \ + ChangeLog INSTALL NEWS compile config.guess config.sub depcomp \ + install-sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +ALLEGRO_CONFIG = @ALLEGRO_CONFIG@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EXEEXT = @EXEEXT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +allegro_CFLAGS = @allegro_CFLAGS@ +allegro_LIBS = @allegro_LIBS@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = src +all: all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ + dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \ + distclean distclean-generic distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-am install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags tags-recursive uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/README b/README new file mode 100644 index 000000000..e69de29bb diff --git a/Readme-LINUX.txt b/Readme-LINUX.txt new file mode 100644 index 000000000..c52f741c8 --- /dev/null +++ b/Readme-LINUX.txt @@ -0,0 +1,31 @@ +PCem v8.1 Linux supplement + + +You will need the following libraries : + +Allegro 4.x +OpenAL +ALut + +and their dependencies. + +Open a terminal window, navigate to the PCem directory then enter + +./configure +make + +then ./pcem to run. + + +The Linux port is currently entirely unpolished, and mainly exists as a starting point for +anyone who wants to make a better port. + +The menu is not available all the time. Press CTRL-ALT-PGDN to open it. + +The mouse does not work very well, at least on my machine. This is most likely an Allegro issue. + +Fullscreen mode is not present. + +Video acceleration is not used at all, so performance is inferior to the Windows version. + +CD-ROM support currently only accesses /dev/cdrom. It has not been heavily tested. diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 000000000..0b87a57fe --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1179 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.65],, +[m4_warning([this file was generated for autoconf 2.65. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Configure paths for Allegro +# Shamelessly stolen from libxml.a4 +# Jon Rafkind 2004-06-06 +# Adapted from: +# Configure paths for libXML +# Toshio Kuratomi 2001-04-21 +# Adapted from: +# Configure paths for GLIB +# Owen Taylor 97-11-3 + +dnl AM_PATH_allegro([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for allegro, and define allegro_CFLAGS and allegro_LIBS +dnl +AC_DEFUN([AM_PATH_ALLEGRO],[ +AC_ARG_WITH(allegro-prefix, + [ --with-allegro-prefix=PFX Prefix where liballegro is installed (optional)], + ALLEGRO_CONFIG_prefix="$withval", ALLEGRO_CONFIG_prefix="") +AC_ARG_WITH(allegro-exec-prefix, + [ --with-allegro-exec-prefix=PFX Exec prefix where liballegro is installed (optional)], + ALLEGRO_CONFIG_exec_prefix="$withval", ALLEGRO_CONFIG_exec_prefix="") +AC_ARG_ENABLE(allegrotest, + [ --disable-allegrotest Do not try to compile and run a test LIBallegro program],, + enable_allegrotest=yes) + + if test x$ALLEGRO_CONFIG_exec_prefix != x ; then + ALLEGRO_CONFIG_args="$ALLEGRO_CONFIG_args --exec-prefix=$ALLEGRO_CONFIG_exec_prefix" + if test x${ALLEGRO_CONFIG+set} != xset ; then + ALLEGRO_CONFIG=$ALLEGRO_CONFIG_exec_prefix/bin/allegro-config + fi + fi + if test x$ALLEGRO_CONFIG_prefix != x ; then + ALLEGRO_CONFIG_args="$ALLEGRO_CONFIG_args --prefix=$ALLEGRO_CONFIG_prefix" + if test x${ALLEGRO_CONFIG+set} != xset ; then + ALLEGRO_CONFIG=$ALLEGRO_CONFIG_prefix/bin/allegro-config + fi + fi + + AC_PATH_PROG(ALLEGRO_CONFIG, allegro-config, no) + min_allegro_version=ifelse([$1], ,4.0.0,[$1]) + AC_MSG_CHECKING(for Allegro - version >= $min_allegro_version) + no_allegro="" + if test "$ALLEGRO_CONFIG" = "no" ; then + no_allegro=yes + else + allegro_CFLAGS=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --cflags` + allegro_LIBS=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --libs` + ALLEGRO_CONFIG_major_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ALLEGRO_CONFIG_minor_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ALLEGRO_CONFIG_micro_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_allegrotest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $allegro_CFLAGS" + LIBS="$allegro_LIBS $LIBS" +dnl +dnl Now check if the installed liballegro is sufficiently new. +dnl (Also sanity checks the results of allegro-config to some extent) +dnl + rm -f conf.allegrotest + AC_TRY_RUN([ +#include +#include +#include +#include + +int +main() +{ + int allegro_major_version, allegro_minor_version, allegro_micro_version; + int major, minor, micro; + char *tmp_version; + int tmp_int_version; + + system("touch conf.allegrotest"); + + /* Capture allegro-config output via autoconf/configure variables */ + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = (char *)strdup("$min_allegro_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string from allegro-config\n", "$min_allegro_version"); + free(tmp_version); + exit(1); + } + free(tmp_version); + + /* Capture the version information from the header files */ + allegro_major_version = ALLEGRO_VERSION; + allegro_minor_version = ALLEGRO_SUB_VERSION; + allegro_micro_version = ALLEGRO_WIP_VERSION; + + /* Compare allegro-config output to the Allegro headers */ + if ((allegro_major_version != $ALLEGRO_CONFIG_major_version) || + (allegro_minor_version != $ALLEGRO_CONFIG_minor_version)) + + { + printf("*** Allegro header files (version %d.%d.%d) do not match\n", + allegro_major_version, allegro_minor_version, allegro_micro_version); + printf("*** allegro-config (version %d.%d.%d)\n", + $ALLEGRO_CONFIG_major_version, $ALLEGRO_CONFIG_minor_version, $ALLEGRO_CONFIG_micro_version); + return 1; + } +/* Compare the headers to the library to make sure we match */ + /* Less than ideal -- doesn't provide us with return value feedback, + * only exits if there's a serious mismatch between header and library. + */ + /* TODO: + * This doesnt work! + */ + /* ALLEGRO_TEST_VERSION; */ + + /* Test that the library is greater than our minimum version */ + if (($ALLEGRO_CONFIG_major_version > major) || + (($ALLEGRO_CONFIG_major_version == major) && ($ALLEGRO_CONFIG_minor_version > minor)) || + (($ALLEGRO_CONFIG_major_version == major) && ($ALLEGRO_CONFIG_minor_version == minor) && + ($ALLEGRO_CONFIG_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of Allegro (%d.%d.%d) was found.\n", + allegro_major_version, allegro_minor_version, allegro_micro_version); + printf("*** You need a version of Allegro newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** Allegro is always available from http://alleg.sf.net.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the allegro-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of Allegro, but you can also set the ALLEGRO_CONFIG environment to point to the\n"); + printf("*** correct copy of allegro-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + return 1; +} END_OF_MAIN() +],, no_allegro=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + if test "x$no_allegro" = x ; then + AC_MSG_RESULT(yes (version $ALLEGRO_CONFIG_major_version.$ALLEGRO_CONFIG_minor_version.$ALLEGRO_CONFIG_micro_version)) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$ALLEGRO_CONFIG" = "no" ; then + echo "*** The allegro-config script installed by Allegro could not be found" + echo "*** If Allegro was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the ALLEGRO_CONFIG environment variable to the" + echo "*** full path to allegro-config." + else + if test -f conf.allegrotest ; then + : + else + echo "*** Could not run Allegro test program, checking why..." + CFLAGS="$CFLAGS $allegro_CFLAGS" + LIBS="$LIBS $allegro_LIBS" + AC_TRY_LINK([ +#include +#include +], [ ALLEGRO_TEST_VERSION; return 0;], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Allegro or finding the wrong" + echo "*** version of Allegro. If it is not finding Allegro, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means Allegro was incorrectly installed" + echo "*** or that you have moved Allegro since it was installed. In the latter case, you" + echo "*** may want to edit the allegro-config script: $ALLEGRO_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + allegro_CFLAGS="" + allegro_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(allegro_CFLAGS) + AC_SUBST(allegro_LIBS) + rm -f conf.allegrotest +]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_PROG_CC_C_O +# -------------- +# Like AC_PROG_CC_C_O, but changed for automake. +AC_DEFUN([AM_PROG_CC_C_O], +[AC_REQUIRE([AC_PROG_CC_C_O])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +dnl Make sure AC_PROG_CC is never called again, or it will override our +dnl setting of CC. +m4_define([AC_PROG_CC], + [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/compile b/compile new file mode 100644 index 000000000..cf0edba28 --- /dev/null +++ b/compile @@ -0,0 +1 @@ +/usr/share/automake-1.11/compile \ No newline at end of file diff --git a/config.guess b/config.guess new file mode 100644 index 000000000..e3a2116a7 --- /dev/null +++ b/config.guess @@ -0,0 +1,1533 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-06-10' + +# 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd | genuineintel) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/config.sub new file mode 100644 index 000000000..eb0389a69 --- /dev/null +++ b/config.sub @@ -0,0 +1,1693 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-06-11' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100644 index 000000000..abbd3d632 --- /dev/null +++ b/configure @@ -0,0 +1,5776 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.65 for PCem v10.1. +# +# Report bugs to >. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and Tom Walker +$0: about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='PCem' +PACKAGE_TARNAME='pcem' +PACKAGE_VERSION='v10.1' +PACKAGE_STRING='PCem v10.1' +PACKAGE_BUGREPORT='Tom Walker ' +PACKAGE_URL='' + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +allegro_LIBS +allegro_CFLAGS +ALLEGRO_CONFIG +OS_LINUX_FALSE +OS_LINUX_TRUE +OS_WIN_FALSE +OS_WIN_TRUE +CPU_X86_64_FALSE +CPU_X86_64_TRUE +CPU_I386_FALSE +CPU_I386_TRUE +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_dependency_tracking +enable_debug +with_allegro_prefix +with_allegro_exec_prefix +enable_allegrotest +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures PCem v10.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/pcem] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of PCem v10.1:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-debug build debug executable + --disable-allegrotest Do not try to compile and run a test LIBallegro program + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-allegro-prefix=PFX Prefix where liballegro is installed (optional) + --with-allegro-exec-prefix=PFX Exec prefix where liballegro is installed (optional) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to >. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +PCem configure v10.1 +generated by GNU Autoconf 2.65 + +Copyright (C) 2009 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by PCem $as_me v10.1, which was +generated by GNU Autoconf 2.65. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done +done +if test -z "$ac_aux_dir"; then + as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='pcem' + VERSION='v10.1' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "C compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +if test "x$CC" != xcc; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 +$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 +$as_echo_n "checking whether cc understands -c and -o together... " >&6; } +fi +set dummy $CC; ac_cc=`$as_echo "$2" | + sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' +rm -f conftest2.* +if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if { ac_try='cc -c conftest.$ac_ext >&5' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' + rm -f conftest2.* + if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f core conftest* + +fi +if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h + +fi + +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable debugging" >&5 +$as_echo_n "checking whether to enable debugging... " >&6; } +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then : + enableval=$enable_debug; +fi + +if test "$enable_debug" = "yes"; then + CFLAGS="-Wall -O0 -g -D_DEBUG" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + CFLAGS="-O3" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cpu" >&5 +$as_echo_n "checking for cpu... " >&6; } +case "${host_cpu}" in + i?86) + CPU=i386 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${host_cpu}" >&5 +$as_echo "${host_cpu}" >&6; } + ;; + x86_64) + CPU=x86_64 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${host_cpu}" >&5 +$as_echo "${host_cpu}" >&6; } + ;; + *) + as_fn_error "Unsupported CPU." "$LINENO" 5 + ;; +esac + + if test "$CPU" = "i386"; then + CPU_I386_TRUE= + CPU_I386_FALSE='#' +else + CPU_I386_TRUE='#' + CPU_I386_FALSE= +fi + + if test "$CPU" = "x86_64"; then + CPU_X86_64_TRUE= + CPU_X86_64_FALSE='#' +else + CPU_X86_64_TRUE='#' + CPU_X86_64_FALSE= +fi + + +#AC_MSG_CHECKING([for libz]) +#AX_CHECK_ZLIB + + if test "$OS" = "win"; then + OS_WIN_TRUE= + OS_WIN_FALSE='#' +else + OS_WIN_TRUE='#' + OS_WIN_FALSE= +fi + + if test "$OS" = "linux"; then + OS_LINUX_TRUE= + OS_LINUX_FALSE='#' +else + OS_LINUX_TRUE='#' + OS_LINUX_FALSE= +fi + + +# Do not run test for Allegro with Win32/MinGW version, as binary builds have +# `allegro-config' missing. +# NOTE: For the following Autoconf macro to be supported, you need to extract +# allegro.m4 from the DOS/Windows Allegro sources (the file is contained +# in `misc') and copy it to this directory or MSYS's `/share/aclocal'. +if test "$OS" != "win"; then + + + +# Check whether --with-allegro-prefix was given. +if test "${with_allegro_prefix+set}" = set; then : + withval=$with_allegro_prefix; ALLEGRO_CONFIG_prefix="$withval" +else + ALLEGRO_CONFIG_prefix="" +fi + + +# Check whether --with-allegro-exec-prefix was given. +if test "${with_allegro_exec_prefix+set}" = set; then : + withval=$with_allegro_exec_prefix; ALLEGRO_CONFIG_exec_prefix="$withval" +else + ALLEGRO_CONFIG_exec_prefix="" +fi + +# Check whether --enable-allegrotest was given. +if test "${enable_allegrotest+set}" = set; then : + enableval=$enable_allegrotest; +else + enable_allegrotest=yes +fi + + + if test x$ALLEGRO_CONFIG_exec_prefix != x ; then + ALLEGRO_CONFIG_args="$ALLEGRO_CONFIG_args --exec-prefix=$ALLEGRO_CONFIG_exec_prefix" + if test x${ALLEGRO_CONFIG+set} != xset ; then + ALLEGRO_CONFIG=$ALLEGRO_CONFIG_exec_prefix/bin/allegro-config + fi + fi + if test x$ALLEGRO_CONFIG_prefix != x ; then + ALLEGRO_CONFIG_args="$ALLEGRO_CONFIG_args --prefix=$ALLEGRO_CONFIG_prefix" + if test x${ALLEGRO_CONFIG+set} != xset ; then + ALLEGRO_CONFIG=$ALLEGRO_CONFIG_prefix/bin/allegro-config + fi + fi + + # Extract the first word of "allegro-config", so it can be a program name with args. +set dummy allegro-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_ALLEGRO_CONFIG+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $ALLEGRO_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ALLEGRO_CONFIG="$ALLEGRO_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_ALLEGRO_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_ALLEGRO_CONFIG" && ac_cv_path_ALLEGRO_CONFIG="no" + ;; +esac +fi +ALLEGRO_CONFIG=$ac_cv_path_ALLEGRO_CONFIG +if test -n "$ALLEGRO_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ALLEGRO_CONFIG" >&5 +$as_echo "$ALLEGRO_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + min_allegro_version=4.0.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Allegro - version >= $min_allegro_version" >&5 +$as_echo_n "checking for Allegro - version >= $min_allegro_version... " >&6; } + no_allegro="" + if test "$ALLEGRO_CONFIG" = "no" ; then + no_allegro=yes + else + allegro_CFLAGS=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --cflags` + allegro_LIBS=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --libs` + ALLEGRO_CONFIG_major_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` + ALLEGRO_CONFIG_minor_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` + ALLEGRO_CONFIG_micro_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` + if test "x$enable_allegrotest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $allegro_CFLAGS" + LIBS="$allegro_LIBS $LIBS" + rm -f conf.allegrotest + if test "$cross_compiling" = yes; then : + echo $ac_n "cross compiling; assumed OK... $ac_c" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#include + +int +main() +{ + int allegro_major_version, allegro_minor_version, allegro_micro_version; + int major, minor, micro; + char *tmp_version; + int tmp_int_version; + + system("touch conf.allegrotest"); + + /* Capture allegro-config output via autoconf/configure variables */ + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = (char *)strdup("$min_allegro_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string from allegro-config\n", "$min_allegro_version"); + free(tmp_version); + exit(1); + } + free(tmp_version); + + /* Capture the version information from the header files */ + allegro_major_version = ALLEGRO_VERSION; + allegro_minor_version = ALLEGRO_SUB_VERSION; + allegro_micro_version = ALLEGRO_WIP_VERSION; + + /* Compare allegro-config output to the Allegro headers */ + if ((allegro_major_version != $ALLEGRO_CONFIG_major_version) || + (allegro_minor_version != $ALLEGRO_CONFIG_minor_version)) + + { + printf("*** Allegro header files (version %d.%d.%d) do not match\n", + allegro_major_version, allegro_minor_version, allegro_micro_version); + printf("*** allegro-config (version %d.%d.%d)\n", + $ALLEGRO_CONFIG_major_version, $ALLEGRO_CONFIG_minor_version, $ALLEGRO_CONFIG_micro_version); + return 1; + } +/* Compare the headers to the library to make sure we match */ + /* Less than ideal -- doesn't provide us with return value feedback, + * only exits if there's a serious mismatch between header and library. + */ + /* TODO: + * This doesnt work! + */ + /* ALLEGRO_TEST_VERSION; */ + + /* Test that the library is greater than our minimum version */ + if (($ALLEGRO_CONFIG_major_version > major) || + (($ALLEGRO_CONFIG_major_version == major) && ($ALLEGRO_CONFIG_minor_version > minor)) || + (($ALLEGRO_CONFIG_major_version == major) && ($ALLEGRO_CONFIG_minor_version == minor) && + ($ALLEGRO_CONFIG_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of Allegro (%d.%d.%d) was found.\n", + allegro_major_version, allegro_minor_version, allegro_micro_version); + printf("*** You need a version of Allegro newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** Allegro is always available from http://alleg.sf.net.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the allegro-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of Allegro, but you can also set the ALLEGRO_CONFIG environment to point to the\n"); + printf("*** correct copy of allegro-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + return 1; +} END_OF_MAIN() + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + no_allegro=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + if test "x$no_allegro" = x ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $ALLEGRO_CONFIG_major_version.$ALLEGRO_CONFIG_minor_version.$ALLEGRO_CONFIG_micro_version)" >&5 +$as_echo "yes (version $ALLEGRO_CONFIG_major_version.$ALLEGRO_CONFIG_minor_version.$ALLEGRO_CONFIG_micro_version)" >&6; } + : + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + if test "$ALLEGRO_CONFIG" = "no" ; then + echo "*** The allegro-config script installed by Allegro could not be found" + echo "*** If Allegro was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the ALLEGRO_CONFIG environment variable to the" + echo "*** full path to allegro-config." + else + if test -f conf.allegrotest ; then + : + else + echo "*** Could not run Allegro test program, checking why..." + CFLAGS="$CFLAGS $allegro_CFLAGS" + LIBS="$LIBS $allegro_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + ALLEGRO_TEST_VERSION; return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Allegro or finding the wrong" + echo "*** version of Allegro. If it is not finding Allegro, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" +else + echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means Allegro was incorrectly installed" + echo "*** or that you have moved Allegro since it was installed. In the latter case, you" + echo "*** may want to edit the allegro-config script: $ALLEGRO_CONFIG" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + allegro_CFLAGS="" + allegro_LIBS="" + as_fn_error "building PCem requires Allegro to be installed" "$LINENO" 5 + fi + + + rm -f conf.allegrotest + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alGetError in -lopenal" >&5 +$as_echo_n "checking for alGetError in -lopenal... " >&6; } +if test "${ac_cv_lib_openal_alGetError+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lopenal $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char alGetError (); +int +main () +{ +return alGetError (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_openal_alGetError=yes +else + ac_cv_lib_openal_alGetError=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_openal_alGetError" >&5 +$as_echo "$ac_cv_lib_openal_alGetError" >&6; } +if test "x$ac_cv_lib_openal_alGetError" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBOPENAL 1 +_ACEOF + + LIBS="-lopenal $LIBS" + +else + \ + echo "You need to install the OpenAL library." + exit -1 +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alutInit in -lalut" >&5 +$as_echo_n "checking for alutInit in -lalut... " >&6; } +if test "${ac_cv_lib_alut_alutInit+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lalut $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char alutInit (); +int +main () +{ +return alutInit (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_alut_alutInit=yes +else + ac_cv_lib_alut_alutInit=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_alut_alutInit" >&5 +$as_echo "$ac_cv_lib_alut_alutInit" >&6; } +if test "x$ac_cv_lib_alut_alutInit" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBALUT 1 +_ACEOF + + LIBS="-lalut $LIBS" + +else + \ + echo "You need to install the ALUT library." + exit -1 +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +$as_echo_n "checking for pthread_create in -lpthread... " >&6; } +if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_create=yes +else + ac_cv_lib_pthread_pthread_create=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPTHREAD 1 +_ACEOF + + LIBS="-lpthread $LIBS" + +fi + + +ac_config_files="$ac_config_files Makefile src/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CPU_I386_TRUE}" && test -z "${CPU_I386_FALSE}"; then + as_fn_error "conditional \"CPU_I386\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CPU_X86_64_TRUE}" && test -z "${CPU_X86_64_FALSE}"; then + as_fn_error "conditional \"CPU_X86_64\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${OS_WIN_TRUE}" && test -z "${OS_WIN_FALSE}"; then + as_fn_error "conditional \"OS_WIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${OS_LINUX_TRUE}" && test -z "${OS_LINUX_FALSE}"; then + as_fn_error "conditional \"OS_LINUX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by PCem $as_me v10.1, which was +generated by GNU Autoconf 2.65. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to >." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +PCem config.status v10.1 +configured by $0, generated by GNU Autoconf 2.65, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2009 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + ;; + + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit $? +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 000000000..388f3db76 --- /dev/null +++ b/configure.ac @@ -0,0 +1,69 @@ +# configure.ac for PCem +# + +AC_PREREQ([2.61]) +AC_INIT(PCem, v10.1, Tom Walker , pcem) + +AC_CANONICAL_HOST + +AM_INIT_AUTOMAKE +AC_PROG_CC +AC_PROG_CXX +AM_PROG_CC_C_O + + + +AC_MSG_CHECKING([whether to enable debugging]) +AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug], [build debug executable])) +if test "$enable_debug" = "yes"; then + CFLAGS="-Wall -O0 -g -D_DEBUG" + AC_MSG_RESULT([yes]) +else + CFLAGS="-O3" + AC_MSG_RESULT([no]) +fi + +AC_MSG_CHECKING([for cpu]) +case "${host_cpu}" in + i?86) + CPU=i386 + AC_MSG_RESULT(${host_cpu}) + ;; + x86_64) + CPU=x86_64 + AC_MSG_RESULT(${host_cpu}) + ;; + *) + AC_MSG_ERROR([Unsupported CPU.]) + ;; +esac + +AM_CONDITIONAL(CPU_I386, test "$CPU" = "i386") +AM_CONDITIONAL(CPU_X86_64, test "$CPU" = "x86_64") + +#AC_MSG_CHECKING([for libz]) +#AX_CHECK_ZLIB + +AM_CONDITIONAL(OS_WIN, test "$OS" = "win") +AM_CONDITIONAL(OS_LINUX, test "$OS" = "linux") + +# Do not run test for Allegro with Win32/MinGW version, as binary builds have +# `allegro-config' missing. +# NOTE: For the following Autoconf macro to be supported, you need to extract +# allegro.m4 from the DOS/Windows Allegro sources (the file is contained +# in `misc') and copy it to this directory or MSYS's `/share/aclocal'. +if test "$OS" != "win"; then + AM_PATH_ALLEGRO(, , AC_MSG_ERROR(building PCem requires Allegro to be installed)) +fi + +AC_CHECK_LIB([openal], [alGetError], [], \ + [echo "You need to install the OpenAL library." + exit -1]) +AC_CHECK_LIB([alut], [alutInit], [], \ + [echo "You need to install the ALUT library." + exit -1]) + +AC_CHECK_LIB([pthread], [pthread_create]) + +AC_OUTPUT([Makefile src/Makefile]) diff --git a/depcomp b/depcomp new file mode 100644 index 000000000..b0ad20c05 --- /dev/null +++ b/depcomp @@ -0,0 +1 @@ +/usr/share/automake-1.11/depcomp \ No newline at end of file diff --git a/install-sh b/install-sh new file mode 100644 index 000000000..205f21c6b --- /dev/null +++ b/install-sh @@ -0,0 +1 @@ +/usr/share/automake-1.11/install-sh \ No newline at end of file diff --git a/missing b/missing new file mode 100644 index 000000000..20bc5b0ed --- /dev/null +++ b/missing @@ -0,0 +1 @@ +/usr/share/automake-1.11/missing \ No newline at end of file diff --git a/nvr/430vx.nvr b/nvr/430vx.nvr new file mode 100644 index 0000000000000000000000000000000000000000..329a958f8926bdfed268ac94bffe499e4010b27d GIT binary patch literal 152 zcmd;J00Cx3#_4KI0Sycc4j?X0%*4RJAc>Hj%^-o`kjH}957EoWz`y{)XW1DT090KA Ai2wiq literal 0 HcmV?d00001 diff --git a/nvr/440fx.nvr b/nvr/440fx.nvr new file mode 100644 index 0000000000000000000000000000000000000000..3b82111ffe0378030b42b6e1332f2428abd0530f GIT binary patch literal 152 zcmdP=@A{whKMNz{jAcv#{}~vZo_t{TZ(w4u(bq5d|DS<@;s5{t{~6ji1^)kU<+SIG zV6c&F015s7|DS*1#aDu#GJ6|3}`zAx%k1A{ID0|P4q0|O%zpJQiW001|mNqztT literal 0 HcmV?d00001 diff --git a/nvr/586mc1.nvr b/nvr/586mc1.nvr new file mode 100644 index 0000000000000000000000000000000000000000..c2562cfa6c8db70579db509a03fab2fe06848f6a GIT binary patch literal 128 zcmZ?x&-9<+KRYAilx0i-{}~vZmVEf{-@wFRW61E~|9=K3xWdf!|NmuXL9XKrHj)kU g_x}I;!2F8&)9e=(|Nno0L(cyU|NrxB{7(u10PQJO2LJ#7 literal 0 HcmV?d00001 diff --git a/nvr/acer386.nvr b/nvr/acer386.nvr new file mode 100644 index 0000000000000000000000000000000000000000..22bff6c1d5f70870d8937eb2ddc3d0166aa25dc0 GIT binary patch literal 128 zcmWGyP+<^dV2}_HRbvYHFTmi!@PWaxfr)|VKLY~;gFOR7iU5cK#mrk7SQHpuF)%Pg J1sMKQ2mm{rM~(mh literal 0 HcmV?d00001 diff --git a/nvr/acerm3a.nvr b/nvr/acerm3a.nvr new file mode 100644 index 0000000000000000000000000000000000000000..578c9f03f540ead904af4050670636d18521d9e5 GIT binary patch literal 128 zcmZ={U||qqU}0pQwv6fje+CAph7b1s4NMGw{xdNDXSiU`*(Siiz`*by0{GGx{z%S$ zbt6}#;h)A6kl4TfYy$uP@BhyY;xzd0XJB9uVEF(4=YNncQGvq@A`FZTAT}oc0}=uN DaS1Ng literal 0 HcmV?d00001 diff --git a/nvr/acerv35n.nvr b/nvr/acerv35n.nvr new file mode 100644 index 0000000000000000000000000000000000000000..a153ab477e30ad3aa560276a8377ebd74821bd75 GIT binary patch literal 128 zcmWIgKlQ)hf2OHZL)Do6|7T!uc&woB-@wH1hk=1vfZ>AuaV7x<1_p-z5Wr*1@JE5+ q)r(wF_J3YrAx3@|rvipQ49p-^4IUtpfkEcfe?|!FFb{;rNdf@ket0~14yzW#q^f&c$G{xjSEXLf)vPL&IF+V literal 0 HcmV?d00001 diff --git a/nvr/cmdpc30.nvr b/nvr/cmdpc30.nvr new file mode 100644 index 0000000000000000000000000000000000000000..3e6551836d0acdee935ee5d1a4db0a967e6d2aca GIT binary patch literal 128 zcmXr{ul`@)KPxkbP#c58e*p#;1_lPl1||j`1_+RZP*9Rlhk@t+{{INjh+vY(0s!fh BQ@H>D literal 0 HcmV?d00001 diff --git a/nvr/dell200.nvr b/nvr/dell200.nvr new file mode 100644 index 0000000000000000000000000000000000000000..b16f18490881a1fcf6115c6dfe6d788aa8d1237a GIT binary patch literal 128 xcmZ=|;9wAEU=tS-WMgt@Fko=`&+y-|fr)|VKQ#-0|Nk{FA1># literal 0 HcmV?d00001 diff --git a/nvr/dtk486.nvr b/nvr/dtk486.nvr new file mode 100644 index 0000000000000000000000000000000000000000..81762a976be1e12dfdfe6a184eef79a209b215f8 GIT binary patch literal 152 zcmdP+ulAqwKNCCSbTy`c{|pR5TRt%PHZU>77&5H-|DOR0{xb^v|NoECo{NJaMzY~Q z1TYtOypVYDpZ~|F|EvuEA3y|u|JS|;VTtYn(QF_B50+tIV31;9VBln6U|?rpU|?im KU^vUpzyJW{G*kKj literal 0 HcmV?d00001 diff --git a/nvr/endeavor.nvr b/nvr/endeavor.nvr new file mode 100644 index 0000000000000000000000000000000000000000..a46ee6710e3cee4865929c51cc57d4297ef44214 GIT binary patch literal 152 zcmY%SAN-&5KNCCS^kobI{}~uuCJHe4H!v~$VNm%0|38N%0}5ahVECiZ@`3sPe-vRn zoMS=^Obm=*1p*8V4PXWXgA>CCF3Sc62Id3_1_lOG1_lOB1_lOp1_rRwv+N8E0OE`l AzyJUM literal 0 HcmV?d00001 diff --git a/nvr/europc.nvr b/nvr/europc.nvr new file mode 100644 index 0000000000000000000000000000000000000000..6757695ca168082f313ed8039d8ac72f31c9c71f GIT binary patch literal 16 UcmZQzU|?kIU;qID1_1^}00x2ptN;K2 literal 0 HcmV?d00001 diff --git a/nvr/hot-433.nvr b/nvr/hot-433.nvr new file mode 100644 index 0000000000000000000000000000000000000000..104e7113c83e552a38ca1f0581ce59cca41bed37 GIT binary patch literal 128 zcmd=5AM{`GKdTUnuo{EIe+Ev6-5(xsH!v~$(Pvn|FYy2W0)Bf228RFt85kHC4l#3m zWcVYw`u_*!1`wZtf$gR|$uv`JCW9iIs2W2+0|SE#0|O&N0}}%a13F*s2@c+mE|Nlz= w|NpQ5l|kVD|1S*o`ac;3{{R2MX#Zc%0;FD@fq{XA0Rk8q7#KkKEIR`O0Iv^6bpQYW literal 0 HcmV?d00001 diff --git a/nvr/mb500n.nvr b/nvr/mb500n.nvr new file mode 100644 index 0000000000000000000000000000000000000000..7564c0cb94110376b0478a3f222981932fd082cc GIT binary patch literal 152 zcmd=5ukfGkKQoh{*fOSo{|pRHPyRFeH!v~S=<65!|NoUi;Q#+G4EF!o1^)m4$8OKp z&tRj_@E-#B-_3p?IVtmRN5_x<{}1Xx1b+(({{Js8xDdko|DQu*^&H3l|Mh<|3jF{7 ogVA1}0SZ70RJs3iGB7ZRFfcH%F)%PNF)%Q2GcYjJurn|K03s(v&j0`b literal 0 HcmV?d00001 diff --git a/nvr/megapc.nvr b/nvr/megapc.nvr new file mode 100644 index 0000000000000000000000000000000000000000..3892761749d76b8807fd8e730f3f4db75798b544 GIT binary patch literal 128 zcma$2ulZl#KPxkb&@u*x{{jpy#vd3Q8<-e)^cWa80zNP>FxWG|fZ%18^9&4<9~u5L WFf=gz|Ig6C@ShM6V#2553nKtt^-dlD literal 0 HcmV?d00001 diff --git a/nvr/p54tp4xe.nvr b/nvr/p54tp4xe.nvr new file mode 100644 index 0000000000000000000000000000000000000000..544bf833996c886d376e2bdccfb0627c84f7caf3 GIT binary patch literal 152 zcmWIgZ}MN_KeIB6*fOSo{|pQ&5C1dyH!v|+=<6H&|NoUi;Q#+G4EAlD0{{QFa@zA+ zGgv4z{D%PkkF$SBcKrGHr=#Ql|5ZzWd<6+lNMT_3b?^Uw1_lL&0|!7N|H}XW|F8d( qQQ-goAB^^J#((*@AXyUz1_mVt1_mJp1_p5k1_l-e28J4T1_l6cQc6t# literal 0 HcmV?d00001 diff --git a/nvr/p55t2p4.nvr b/nvr/p55t2p4.nvr new file mode 100644 index 0000000000000000000000000000000000000000..2c9b27bffcf4616293cc6868262a840aecd07e4b GIT binary patch literal 152 zcmWIgul`^8Ka&!R*fOSo{|pRH4?i&YH!v~S=<6H&|Ifg{@c;k+{|s%M0{{QFa@z9> zG1w?HfQ0`4|Ih#7;E%wL-+%vfbo~EQ=dHUDBt9X9f#KIZkWK}L0|!7N|4RS=|F8d* yLE!)YFAVnjKN$u7|Np^g|6k4rBx}OJz#z@Qz#z`Rz#zuJz`(-5z)-`^zyJW*Z%7&d literal 0 HcmV?d00001 diff --git a/nvr/p55tp4n.nvr b/nvr/p55tp4n.nvr new file mode 100644 index 0000000000000000000000000000000000000000..0c7ab65fce6b4e0ec5815e622ff863b0faed11e5 GIT binary patch literal 128 zcmWeQ;BbKB06QaN!!o9T|I7?d7e6q#H!v~$(bK7jQa%6$f($Hs7#RNl=Y7WTM^c~p l1M>%mgar%?3};?3cuO+yaC31sG&D3YF!(=U85kHqx)?wV f1_lOshW}F1AOThe1_oxREsP8d3?Q7t&cFZw-BUm= literal 0 HcmV?d00001 diff --git a/nvr/p55va.nvr b/nvr/p55va.nvr new file mode 100644 index 0000000000000000000000000000000000000000..e3e32d6aba93dfb9e428b311c6a271de52df29d6 GIT binary patch literal 152 zcmY%RZ}eZ}KP!u%*fOSo{|pRDPyRFeH!v~$(bq5d|Nkq4!2kbW80_0P1^)kU<+SH> zWcZ`d@E-#BH_m<`8M3nXLw!fbpZy8DL8AXk7(V>B-~WF*i1Yt1GxLN0|NlGx|F6%$ rzyK0r05KRC7#P7k)#U#o3=9kk3=9l>3=9k`3=9n13=9l4> literal 0 HcmV?d00001 diff --git a/nvr/p5sp4.nvr b/nvr/p5sp4.nvr new file mode 100644 index 0000000000000000000000000000000000000000..e1d2c3a9b7be11469f02bda58f8828f5b040823c GIT binary patch literal 128 zcmXr`FY=$^KRYAilx0i-{}~vZo_t{RZ(w5hqtDRr|33p1v~ddj|KG}K&-t6-k7UDt z2w?v-`-Q~*k~^~T)BpV7hKT*Q%)7u7;2My?ATaB_^Z$SUc0TxEFYp0w5Y#*d28Iuf KZ2$T0{09Jc6*$%a literal 0 HcmV?d00001 diff --git a/nvr/pc1512.nvr b/nvr/pc1512.nvr new file mode 100644 index 0000000000000000000000000000000000000000..b1f758b3eb1e48c42a9253b22710a853d1f9c5b0 GIT binary patch literal 128 rcmXqIP-0MKU=tS-WMg1xP*Mi5Qh8$~ literal 0 HcmV?d00001 diff --git a/nvr/pc2086.nvr b/nvr/pc2086.nvr new file mode 100644 index 0000000000000000000000000000000000000000..40f5636007c22b145ac978e02d0dce2e083d23fa GIT binary patch literal 128 icmWG$P-75aU}feIQeblUuOp1||j@Lx%ql0H(pj|5c(g3^tMtC;$Hk^BKO? YLX=QI3NSE$UBJM=z`zK_N7)$|04vI3d;kCd literal 0 HcmV?d00001 diff --git a/nvr/r418.nvr b/nvr/r418.nvr new file mode 100644 index 0000000000000000000000000000000000000000..9edb8061257c280c9e3aefa300a764badea12ad3 GIT binary patch literal 152 zcmY%RZ}4B~KZ~Kz%wL0J(nZHAIXOQ z5WxSh>xJY0+w0@H4p{tu^MK+1{r`{tO32UJ@3`~-fA?t+MNm>7Vvsz8J_Ccm|Nnm& l?EnA&ufp^HzX$^ZgB$|`gBSw?gFFKR0}lfO!+CZF1_1e{M56!z literal 0 HcmV?d00001 diff --git a/nvr/revenge.nvr b/nvr/revenge.nvr new file mode 100644 index 0000000000000000000000000000000000000000..2ee09d49db811859a894a1d1e897f04a2c9ff5f5 GIT binary patch literal 152 zcmY%S&+uR9KNAB3LmNZDe+CAJ$qWoU4NMGw7#jZnXW+JEKmn}s41Xm5e_;OqA4M1s hr)?6lqyj?*0|x^GgA-Jc@s$LW#RH{5R1P}>0|4md62AZd literal 0 HcmV?d00001 diff --git a/nvr/sis496.nvr b/nvr/sis496.nvr new file mode 100644 index 0000000000000000000000000000000000000000..56f19faafe995293687c49a0e9bb780255c5b20e GIT binary patch literal 152 zcmcEcZ~R~IKeIB6m>N^Se+CAXEgzVD8<-d@^!0!J|IYvgZJYxC|F?45b53HgP-yrM z0sQ|vPB8wDUhuEKLE-R=rOGN|DOR0jx!1T|9_0hp7R-ljU>bG z>AJl?m|fUEcD-x(ij+Q($dmwBp4X%jqME#3>X;dlk1a{ zlNlH!ByQV0w_#v#NGPbOuVG+dWM-GImj|0KAtAxQU#NsuuC?OF$3uX z+suGaCt*_uRxbetAXy%^dNvR(VNh=Xq8Snr5+S4hK;jTA zVPj(>A;FNGoU8;EFf*$+Gc)7iu}e-&uww=ZB_^}+FfhoNnaNn^F&G#afDL8fkuU)J zOM-`ujSXyXn$3S3kOL(o{!4)LA@F|$lYx<$jYq*CxXMR#tak@3=H+g zh9)*92pTM(&j1Rr)9L(?IqyfV~Pf=kQ^O zdC6vwbPNtpP|8l@VPN2skdP>l0Od0Y2?hxUh5`u*2|fu12J1YqUT{VLg#|bs6B!uN z(ilMIv++nU*d^C9aLAZJ!XqsWOdCk>fN2>s88FQN%Gn8NV09q%ApIa3qz*)b_!c0W zZPFM(bb^5dm`+XxML{yi7*Ku&MOD4A0VqE*AZ?ao22!14CT%9@0)e5c zAnnfMl&$jgUvBBgSh9v1ca85_yM+ufk7Tr z4}mb0|NjFN@IwJe?*D(Nb=G+~Aa!=hka9H{T<$S2fXaVRIcp%n11ZPtbHM5#auA#h%@`Qu3?z8$Amv6KsGMSEtGj*sGo<{k0i_c=P>BZ0tqcsH zYE}YNT}Uv15;`akf)XYu&oJ;wgHkFu9Khuus4RfE+d7ZI8j=n{t_NX|9EfI+VBqHg zfj0~{azKEAq2Pu=!U;(5*x7;WKd?d=F|!d|IWRnjR_%5&9AGIZ1xvaJ8Z67e@EjbF z3=C=z!?}+fW?!IWg#@EN(PsL z5c|`h3Bk;`7%UIdcNkRlGa&4NRar3e^6l8zK^lyq`e6Qo7MbvH0$1@23=IFFRbd*` zT$sAV!;rjTU;uFsEM4*NK=>d#U>Kqj!h^-Du`#52On`2--keG(>7#R4V_De|ffz`v@0rUTDa8njs z>VV~w?I9^Z0vb;e5)gf`bRr>909FShpvjEESdNVulmcMp!~6;3dj1d17-?yr!RAXy zNZbI02+TZ~J7M}^;>OT&C>`oWDhd;(4@D51 zk3ljBdtve*QII__8fFhn9v2^%I7}am#$_%pd6>B{edy{ywGgO!htZJgpMe2V{lio< zFy!Px%Jby9gaic!23S`S6uw|Zu<{tx+5-vLLA!mhCOxzoVt}PTGc#B^hLksu)W^V3 zmjJHz7!nLno9f`I9~AD;CX)fQq~?LrF#p{Er&f?cNX-T*r9dvij&p1v_MppR*8C6^ zpx*!9nT>Uz-v8m}|Lb!8{rgvAA;2JDQ3IweYApW!yCz^E02UCi0QJ8?N&5f)=Z6nJ z|NkG{`A@T9_z&v*&piB}pP99`rKP39#>vUaMxsu_UeR7bA>qLRdqsOi<@9FoFn)Px8K2rvi;2!w##%OJt?58PTaNcaco^*T5>fFc3Z`3E%uK<)>%njzkU zc%FfQLBPTSWD0|d3P=$HgNjO>N}Y-dgM^)f4O5K-14B{@hk%+JgMo)ZSVu=0gMa`i zwJ2sl5P%vFQ4DegL;xhg#KIw<;J{$x*wLPH{nT4mJ!D zDo##yPEHIpN=i0LN;M2JN)8SVN-_);DoRR9DisWMN*Wd#N_7xgp#UuJrzFSV1lH!n zU?Bhk77TnWEG#ZA77R%$8U`9F$qWSw3JMBJbqvX&o{o-=jtogbUT#iKPGI|-R3yOm zDJT?x-0$RN!wlwYs1z~SI62sW{9EtI!NI{H1F{E{k{CdSD2Z@@Xira1GX_T`5e^Y0 zM=%XiR}Tso#d?Mc2N0-WXmC&fd6}UCWDG|IgMfxh6C@JAs641mZG)6CQ&AC>aTXTD4A2PHt8V3=EDSFN0{X{}~uuGz2t23C;=Z9tMUQ4grN4 z1|9){1OWjaP`&_T0}c*04h{nbBOj1oL7jgQB}d14P&hl;@G#jhxG=c5xY#l9FhKli z<7B~N<6_6)!~mfUptJy#W?-;!aIj&Mv2lW^cY^9OfYK@q65x2NX@Z1{0hI3~p#n~4 z5)vSVP7FK@H3}9Apf;v4kG+dEgS?7My^D)GgM_!26hqyXlF z(*uJO1IXVtAag70tKfU1{aMQP)IWT@TqX|cX53tBLw13 zNZ^6`hX?9D7EqROvSDCg;Q*U&_pb`M2o`Ipx z0n(MJV`5@pa601gP1CtY-syde04+8@O zNDM>^2z(Iu0Mg9BzyLB2WHhLq0-|B<;r}3xfPjEJ*uf0onh7KX5tj#xgUk~L5hCIO zApHys@&XV(Qs*Bk4-yBN0y1Ajx4-$g}gQ1s;mmw%S);QHT zI55;XfeH==2Kx|@Eev%|3K9xVprYH(!^6XX0hCLs92^=LjD0{Q3PX(ms9qAN0Vit} z32?clqLRiSqaXn;ml=|#c1}%VU|?dg@d~nWXy6f0uu%{ISHOKDVyLX_1!Jy*I znLlUFfQLuZ(*7{mq#ZbLAkBv1M^0K=TFwuKe@Ph?8A<;jbixO){JAtchBIJoXP~3} z6%2AbJUk%xJxj}}$Vq#~@F5`~At~)2!?Ab&{#`qEjN#a`Z}-j}1BK(UW5;qV!1g61 zd;q!s%$*7uFdw9^;!J{p1jwITK;cpWvIk@pgsw1PICkvVwSVu9F@OxQ$T}!v6$~KH^RO{7RDc`O6$}C(#gJG4k^c=0Anj=eh6%|QINYB7|wtKfPsPG$C)!{&VbDWg%bnAowT%?gbz^j!2<&W z83s`QAA~_11A_+)WgxGCd=3hTWB(w&l;EjgI0Fj8ItCeriZdX8)*ZHCvrDsQI0Fus zI)(>O+Q0x5PN4Fz;=q9l9*ereHfePUHXwCieGj1e&wzbi!BBI|LITvcegNekv&cF2 z@7OU=7N|J$=L~}k!=HqT1W?wf=czwa&tR8x=HHn!=NKx^fRaQ71K40twg(w}rUE2> z=FFKo28IU^_cDOoUBmO^FlZFkMgq(Qg{y=_-GKvj5)u|UDIXG^{b4wBrs5AMNB%f- z=GU?F$By$!OW1&h0A!&4vVgh|8~`BuWT58%07n?ZABHn;{@gi(G5l}9V2}VxCkzY> ze-1#pcz-|xhKG-xxo4bqhX3%fGq=t2&oe`dCa-*`G6M#%X78*Z<(;3MC+e z^gkp(G^pPT8srB>;XgCbASFy3Y49H`jx_iWn#?sbGXoWa5)wb)gXAFdKvsb2R}c-U zhZz`PgXy420gyc)aj-mykdOyY7J%FV8SE!w@E`0RNPTZ+_8mMa0Get5nF}%pM1$*p zP(lTb?STZ%%*;R|qM)e>koy=IAohaX10Vc1GcyAXn#0@+8Qlh{l#l?`?;s3P52A6` z|7CYh+$jTP_aA3|95}%6=gffvposhj8aB^i_;V(~08}0`Fx1@u_rXE+Qcc1EhO#@L z&|vrjDmW_){(zHpjs=57&aq=TIqw)`3?ynm>5ze;?)L3E1_m}B5S?%URDK^wumB}) zP=*GT$$vmaGo-rs!;oMADxLo@NEm=h?LVla|2J+F7#J}80c9RgMh4|&P^}2^BVuHL b0W{eM9{zumV +#include +#include +#include "ibm.h" +#include "x86.h" +#include "x87.h" +#include "mem.h" +#include "cpu.h" +#include "fdc.h" +#include "timer.h" + +#include "386_common.h" + +#define CPU_BLOCK_END() + +extern int codegen_flags_changed; + +x86seg *ea_seg; + +extern int nmi_enable; + +int inscounts[256]; +uint32_t oldpc2; + +int trap; + + + +extern int cpl_override; + +int has_fpu; +extern int fpucount; +int times; +uint16_t rds; +uint16_t ea_rseg; + +int is486; +int cgate32; + + + +uint8_t romext[32768]; +uint8_t *ram,*rom; +uint32_t biosmask; + +uint32_t rmdat32; +#define rmdat rmdat32 +#define fetchdat rmdat32 +uint32_t backupregs[16]; +extern int oddeven; +int inttype,abrt; + + +uint32_t oldcs2; +uint32_t oldecx; +uint32_t op32; + + +uint32_t *eal_r, *eal_w; + +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +static inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (rm == 4) + { + uint8_t sib = rmdat >> 8; + + switch (mod) + { + case 0: + eaaddr = cpu_state.regs[sib & 7].l; + cpu_state.pc++; + break; + case 1: + cpu_state.pc++; + eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; +// pc++; + break; + case 2: + eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; + break; + } + /*SIB byte present*/ + if ((sib & 7) == 5 && !mod) + eaaddr = getlong(); + else if ((sib & 6) == 4 && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + if (((sib >> 3) & 7) != 4) + eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); + } + else + { + eaaddr = cpu_state.regs[rm].l; + if (mod) + { + if (rm == 5 && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + if (mod == 1) + { + eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } + else + { + eaaddr += getlong(); + } + } + else if (rm == 5) + { + eaaddr = getlong(); + } + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +static inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (!mod && rm == 6) + { + eaaddr = getword(); + } + else + { + switch (mod) + { + case 0: + eaaddr = 0; + break; + case 1: + eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; + break; + case 2: + eaaddr = getword(); + break; + } + eaaddr += (*mod1add[0][rm]) + (*mod1add[1][rm]); + if (mod1seg[rm] == &ss && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + eaaddr &= 0xFFFF; + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_16_long(rmdat); if (abrt) return 0; } +#define fetch_ea_32(rmdat) cpu_state.pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_32_long(rmdat); } if (abrt) return 0 + +#include "x86_flags.h" + +#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ +#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 +extern int xout; + +int oldi; + +uint32_t testr[9]; +extern int dontprint; + +#undef NOTRM +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + return 0; \ + } + +#define OP_TABLE(name) ops_ ## name + +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "x86_ops.h" + +#undef NOTRM +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + break; \ + } + +void exec386(int cycs) +{ + uint8_t temp; + uint32_t addr; + int tempi; + int cycdiff; + int oldcyc; + + cycles+=cycs; +// output=3; + while (cycles>0) + { + cycdiff=0; + oldcyc=cycles; + timer_start_period(cycles << TIMER_SHIFT); +// pclog("%i %02X\n", ins, ram[8]); + while (cycdiff<100) + { + /* testr[0]=EAX; testr[1]=EBX; testr[2]=ECX; testr[3]=EDX; + testr[4]=ESI; testr[5]=EDI; testr[6]=EBP; testr[7]=ESP;*/ +/* testr[8]=flags;*/ +// oldcs2=oldcs; +// oldpc2=oldpc; +opcode_realstart: + oldcs=CS; + oldpc=cpu_state.pc; + oldcpl=CPL; + op32=use32; + +dontprint=0; + + ea_seg = &_ds; + ssegs = 0; + +opcodestart: + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + if (output == 3) + { + pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %f %02X%02X %02X%02X %02X%02X %02X\n",CS,cs,cpu_state.pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0xB270+0x3F5], ram[0xB270+0x3F4], ram[0xB270+0x3F7], ram[0xB270+0x3F6], ram[0xB270+0x3F9], ram[0xB270+0x3F8], ram[0x4430+0x0D49]); + } + cpu_state.pc++; + x86_opcodes[(opcode | op32) & 0x3ff](fetchdat); + } + + if (!use32) cpu_state.pc &= 0xffff; + + if (abrt) + { + flags_rebuild(); +// pclog("Abort\n"); +// if (CS == 0x228) pclog("Abort at %04X:%04X - %i %i %i\n",CS,pc,notpresent,nullseg,abrt); +/* if (testr[0]!=EAX) pclog("EAX corrupted %08X\n",pc); + if (testr[1]!=EBX) pclog("EBX corrupted %08X\n",pc); + if (testr[2]!=ECX) pclog("ECX corrupted %08X\n",pc); + if (testr[3]!=EDX) pclog("EDX corrupted %08X\n",pc); + if (testr[4]!=ESI) pclog("ESI corrupted %08X\n",pc); + if (testr[5]!=EDI) pclog("EDI corrupted %08X\n",pc); + if (testr[6]!=EBP) pclog("EBP corrupted %08X\n",pc); + if (testr[7]!=ESP) pclog("ESP corrupted %08X\n",pc);*/ +/* if (testr[8]!=flags) pclog("FLAGS corrupted %08X\n",pc);*/ + tempi = abrt; + abrt = 0; + x86_doabrt(tempi); + if (abrt) + { + abrt = 0; + CS = oldcs; + cpu_state.pc = oldpc; + pclog("Double fault %i\n", ins); + pmodeint(8, 0); + if (abrt) + { + abrt = 0; + softresetx86(); + pclog("Triple fault - reset\n"); + } + } + } + cycdiff=oldcyc-cycles; + + if (trap) + { + flags_rebuild(); +// oldpc=pc; +// oldcs=CS; + if (msw&1) + { + pmodeint(1,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (1 << 2) + idt.base; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + else if (nmi && nmi_enable) + { + oldpc = cpu_state.pc; + oldcs = CS; +// pclog("NMI\n"); + x86_int(2); + nmi_enable = 0; + } + else if ((flags&I_FLAG) && pic_intpending) + { + temp=picinterrupt(); + if (temp!=0xFF) + { +// if (temp == 0x54) pclog("Take int 54\n"); +// if (output) output=3; +// if (temp == 0xd) pclog("Hardware int %02X %i %04X(%08X):%08X\n",temp,ins, CS,cs,pc); +// if (temp==0x54) output=3; + flags_rebuild(); + if (msw&1) + { + pmodeint(temp,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (temp << 2) + idt.base; + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); +// if (temp==0x76) pclog("INT to %04X:%04X\n",CS,pc); + } +// pclog("Now at %04X(%08X):%08X\n", CS, cs, pc); + } + } + + ins++; + insc++; + + if (timetolive) + { + timetolive--; + if (!timetolive) + fatal("Life expired\n"); + } + } + + tsc += cycdiff; + + timer_end_period(cycles << TIMER_SHIFT); + } +} diff --git a/src/386.h b/src/386.h new file mode 100644 index 000000000..d374f3c9e --- /dev/null +++ b/src/386.h @@ -0,0 +1,2 @@ +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); diff --git a/src/386_common.h b/src/386_common.h new file mode 100644 index 000000000..f02a64b9d --- /dev/null +++ b/src/386_common.h @@ -0,0 +1,288 @@ +extern uint16_t ea_rseg; + +#undef readmemb +#undef writememb + + +#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)?readmemb386l(s,a): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) ) +#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFF8)?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) + +#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememb386l(s,a,v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v + +#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFF8) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v + + +#if 0 +#define check_io_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \ + { \ + int tempi = checkio(port); \ + if (abrt) return 1; \ + if (tempi) \ + { \ + pclog("No I/O permission on port %04Xh\n", port); \ + x86gpf("check_io_perm(): no permission",0); \ + return 1; \ + } \ + } + +#define checkio_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \ + { \ + tempi = checkio(port); \ + if (abrt) break; \ + if (tempi) \ + { \ + x86gpf("checkio_perm(): no permission",0); \ + break; \ + } \ + } +#endif + +#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ + { \ + int tempi = checkio(port); \ + if (abrt) return 1; \ + if (tempi) \ + { \ + pclog("No I/O permission on port %04Xh\n", port); \ + x86gpf("check_io_perm(): no permission",0); \ + return 1; \ + } \ + } + +#define checkio_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ + { \ + tempi = checkio(port); \ + if (abrt) break; \ + if (tempi) \ + { \ + x86gpf("checkio_perm(): no permission",0); \ + break; \ + } \ + } + +#define CHECK_READ(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (READ)", 0); \ + return 1; \ + } \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + pclog("Read from seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } + +#define CHECK_WRITE(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2)) \ + { \ + x86gpf("Limit check (WRITE)", 0); \ + return 1; \ + } \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write to seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } + +#if 0 +#define CHECK_WRITE_REP(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (WRITE_REP)", 0); \ + if (1 != 1) break; \ + } \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } +#endif + +#define CHECK_WRITE_REP(chseg, low, high) \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } + + +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + return 1; \ + } + + + + +static inline uint8_t fastreadb(uint32_t a) +{ + uint8_t *t; + + if ((a >> 12) == pccache) + return *((uint8_t *)&pccache2[a]); + t = getpccache(a); + if (abrt) + return; + pccache = a >> 12; + pccache2 = t; + return *((uint8_t *)&pccache2[a]); +} + +static inline uint16_t fastreadw(uint32_t a) +{ + uint8_t *t; + uint16_t val; + if ((a&0xFFF)>0xFFE) + { + val = readmemb(0, a); + val |= (readmemb(0, a + 1) << 8); + return val; + } + if ((a>>12)==pccache) return *((uint16_t *)&pccache2[a]); + t = getpccache(a); + if (abrt) + return; + + pccache = a >> 12; + pccache2 = t; + return *((uint16_t *)&pccache2[a]); +} + +static inline uint32_t fastreadl(uint32_t a) +{ + uint8_t *t; + uint32_t val; + if ((a&0xFFF)<0xFFD) + { + if ((a>>12)!=pccache) + { + t = getpccache(a); + if (abrt) + return 0; + pccache2 = t; + pccache=a>>12; + //return *((uint32_t *)&pccache2[a]); + } + return *((uint32_t *)&pccache2[a]); + } + val =readmemb(0,a); + val |=(readmemb(0,a+1)<<8); + val |=(readmemb(0,a+2)<<16); + val |=(readmemb(0,a+3)<<24); + return val; +} + +static inline uint8_t getbyte() +{ + cpu_state.pc++; + return fastreadb(cs + (cpu_state.pc - 1)); +} + +static inline uint16_t getword() +{ + cpu_state.pc+=2; + return fastreadw(cs+(cpu_state.pc-2)); +} + +static inline uint32_t getlong() +{ + cpu_state.pc+=4; + return fastreadl(cs+(cpu_state.pc-4)); +} + +static inline uint64_t getquad() +{ + cpu_state.pc+=8; + return fastreadl(cs+(cpu_state.pc-8)) | ((uint64_t)fastreadl(cs+(cpu_state.pc-4)) << 32); +} + + + +static inline uint8_t geteab() +{ + if (mod == 3) + return (rm & 4) ? cpu_state.regs[rm & 3].b.h : cpu_state.regs[rm&3].b.l; + if (eal_r) + return *(uint8_t *)eal_r; + return readmemb(easeg, eaaddr); +} + +static inline uint16_t geteaw() +{ + if (mod == 3) + return cpu_state.regs[rm].w; +// cycles-=3; + if (eal_r) + return *(uint16_t *)eal_r; + return readmemw(easeg, eaaddr); +} + +static inline uint32_t geteal() +{ + if (mod == 3) + return cpu_state.regs[rm].l; +// cycles-=3; + if (eal_r) + return *eal_r; + return readmeml(easeg, eaaddr); +} + +static inline uint64_t geteaq() +{ + return readmemq(easeg, eaaddr); +} + +static inline uint8_t geteab_mem() +{ + if (eal_r) return *(uint8_t *)eal_r; + return readmemb(easeg,eaaddr); +} +static inline uint16_t geteaw_mem() +{ + if (eal_r) return *(uint16_t *)eal_r; + return readmemw(easeg,eaaddr); +} +static inline uint32_t geteal_mem() +{ + if (eal_r) return *eal_r; + return readmeml(easeg,eaaddr); +} + +static inline void seteaq(uint64_t v) +{ + writememql(easeg, eaaddr, v); +} + +#define seteab(v) if (mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,eaaddr,v); } else if (rm&4) cpu_state.regs[rm&3].b.h=v; else cpu_state.regs[rm].b.l=v +#define seteaw(v) if (mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,eaaddr,v); } else cpu_state.regs[rm].w=v +#define seteal(v) if (mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg,eaaddr,v); } else cpu_state.regs[rm].l=v + +#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,eaaddr,v); +#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,eaaddr,v); +#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,eaaddr,v); + +#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ +#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 + + +#define rmdat rmdat32 +#define fetchdat rmdat32 + +void x86_int(int num); diff --git a/src/386_dynarec.c b/src/386_dynarec.c new file mode 100644 index 000000000..ee9d33f1b --- /dev/null +++ b/src/386_dynarec.c @@ -0,0 +1,1544 @@ +#include +#include +#include +#include "ibm.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" +#include "cpu.h" +#include "fdc.h" +#include "timer.h" + +#include "386_common.h" + +#define CPU_BLOCK_END() cpu_block_end = 1 + +int cpu_reps, cpu_reps_latched; +int cpu_notreps, cpu_notreps_latched; + +int inrecomp = 0; +int cpu_recomp_blocks, cpu_recomp_ins, cpu_recomp_full_ins, cpu_new_blocks; +int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; + +int cpu_block_end = 0; + +x86seg *ea_seg; + +int nmi_enable = 1; + +int inscounts[256]; +uint32_t oldpc2; + +int trap; + + + +int cpl_override=0; + +int has_fpu; +int fpucount=0; +int times; +uint16_t rds; +uint16_t ea_rseg; + +int is486; +int cgate32; + + +uint8_t romext[32768]; +uint8_t *ram,*rom; +uint32_t biosmask; + +uint32_t rmdat32; +uint32_t backupregs[16]; +int oddeven=0; +int inttype,abrt; + + +uint32_t oldcs2; +uint32_t oldecx; +uint32_t op32; + + + + +uint32_t *eal_r, *eal_w; + +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +static inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (rm == 4) + { + uint8_t sib = rmdat >> 8; + + switch (mod) + { + case 0: + eaaddr = cpu_state.regs[sib & 7].l; + cpu_state.pc++; + break; + case 1: + cpu_state.pc++; + eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; +// cpu_state.pc++; + break; + case 2: + eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; + break; + } + /*SIB byte present*/ + if ((sib & 7) == 5 && !mod) + eaaddr = getlong(); + else if ((sib & 6) == 4 && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + if (((sib >> 3) & 7) != 4) + eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); + } + else + { + eaaddr = cpu_state.regs[rm].l; + if (mod) + { + if (rm == 5 && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + if (mod == 1) + { + eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } + else + { + eaaddr += getlong(); + } + } + else if (rm == 5) + { + eaaddr = getlong(); + } + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +static inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (!mod && rm == 6) + { + eaaddr = getword(); + } + else + { + switch (mod) + { + case 0: + eaaddr = 0; + break; + case 1: + eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; + break; + case 2: + eaaddr = getword(); + break; + } + eaaddr += (*mod1add[0][rm]) + (*mod1add[1][rm]); + if (mod1seg[rm] == &ss && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + eaaddr &= 0xFFFF; + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_16_long(rmdat); if (abrt) return 1; } +#define fetch_ea_32(rmdat) cpu_state.pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_32_long(rmdat); } if (abrt) return 1 + +#include "x86_flags.h" + +void x86_int(int num) +{ + uint32_t addr; +// pclog("x86_int %02x %04x:%04x\n", num, CS,pc); + flags_rebuild(); + cpu_state.pc=oldpc; + if (msw&1) + { + pmodeint(num,0); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + addr = (num << 2) + idt.base; + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + cycles-=70; + CPU_BLOCK_END(); +} + +void x86_int_sw(int num) +{ + uint32_t addr; +// pclog("x86_int_sw %02x %04x:%04x\n", num, CS,pc); +// pclog("x86_int\n"); + flags_rebuild(); + cycles -= timing_int; + if (msw&1) + { + pmodeint(num,1); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + addr = (num << 2) + idt.base; + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles -= timing_int_rm; + } + trap = 0; + CPU_BLOCK_END(); +} + +void x86illegal() +{ + uint16_t addr; +// pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode); + +// if (output) +// { +// dumpregs(); +// exit(-1); +// } + x86_int(6); +} + + +int rep386(int fv) +{ + uint8_t temp; + uint32_t c;//=CX; + uint8_t temp2; + uint16_t tempw,tempw2,of; + uint32_t ipc=oldpc;//pc-1; + uint32_t oldds; + uint32_t rep32=op32; + uint32_t templ,templ2; + int tempz; + int tempi; + /*Limit the amount of time the instruction is uninterruptable for, so + that high frequency timers still work okay. This amount is different + for interpreter and recompiler*/ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); + + cpu_reps++; + + flags_rebuild(); + of = flags; +// if (inrecomp) pclog("REP32 %04X %04X ",use32,rep32); + startrep: + temp=opcode2=readmemb(cs,cpu_state.pc); cpu_state.pc++; +// if (firstrepcycle && temp==0xA5) pclog("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); +// if (inrecomp) pclog("REP %02X %04X\n",temp,ipc); + c=(rep32&0x200)?ECX:CX; +/* if (rep32 && (msw&1)) + { + if (temp!=0x67 && temp!=0x66 && (rep32|temp)!=0x1AB && (rep32|temp)!=0x3AB) pclog("32-bit REP %03X %08X %04X:%06X\n",temp|rep32,c,CS,pc); + }*/ + switch (temp|rep32) + { + case 0xC3: case 0x1C3: case 0x2C3: case 0x3C3: + cpu_state.pc--; + break; + case 0x08: + cpu_state.pc=ipc+1; + break; + case 0x26: case 0x126: case 0x226: case 0x326: /*ES:*/ + ea_seg = &_es; + goto startrep; + break; + case 0x2E: case 0x12E: case 0x22E: case 0x32E: /*CS:*/ + ea_seg = &_cs; + goto startrep; + case 0x36: case 0x136: case 0x236: case 0x336: /*SS:*/ + ea_seg = &_ss; + goto startrep; + case 0x3E: case 0x13E: case 0x23E: case 0x33E: /*DS:*/ + ea_seg = &_ds; + goto startrep; + case 0x64: case 0x164: case 0x264: case 0x364: /*FS:*/ + ea_seg = &_fs; + goto startrep; + case 0x65: case 0x165: case 0x265: case 0x365: /*GS:*/ + ea_seg = &_gs; + goto startrep; + case 0x66: case 0x166: case 0x266: case 0x366: /*Data size prefix*/ + rep32 = (rep32 & 0x200) | ((use32 ^ 0x100) & 0x100); + goto startrep; + case 0x67: case 0x167: case 0x267: case 0x367: /*Address size prefix*/ + rep32 = (rep32 & 0x100) | ((use32 ^ 0x200) & 0x200); + goto startrep; + case 0x6C: case 0x16C: /*REP INSB*/ +// cpu_notreps++; + if (c>0) + { + checkio_perm(DX); + temp2=inb(DX); + writememb(es,DI,temp2); + if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x26C: case 0x36C: /*REP INSB*/ +// cpu_notreps++; + if (c>0) + { + checkio_perm(DX); + temp2=inb(DX); + writememb(es,EDI,temp2); + if (abrt) break; + if (flags&D_FLAG) EDI--; + else EDI++; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x6D: /*REP INSW*/ +// cpu_notreps++; + if (c>0) + { +// pclog("REP INSW %04x %04x:%04x %04x\n", DX, ES, DI, CX); + tempw=inw(DX); + writememw(es,DI,tempw); + if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x16D: /*REP INSL*/ +// cpu_notreps++; + if (c>0) + { + templ=inl(DX); + writememl(es,DI,templ); + if (abrt) break; + if (flags&D_FLAG) DI-=4; + else DI+=4; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x26D: /*REP INSW*/ +// cpu_notreps++; + if (c>0) + { + tempw=inw(DX); + writememw(es,EDI,tempw); + if (abrt) break; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x36D: /*REP INSL*/ +// cpu_notreps++; + if (c>0) + { + templ=inl(DX); + writememl(es,EDI,templ); + if (abrt) break; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x6E: case 0x16E: /*REP OUTSB*/ +// cpu_notreps++; + if (c>0) + { + temp2 = readmemb(ea_seg->base, SI); + if (abrt) break; + checkio_perm(DX); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x26E: case 0x36E: /*REP OUTSB*/ +// cpu_notreps++; + if (c>0) + { + temp2 = readmemb(ea_seg->base, ESI); + if (abrt) break; + checkio_perm(DX); + outb(DX,temp2); + if (flags&D_FLAG) ESI--; + else ESI++; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x6F: /*REP OUTSW*/ +// cpu_notreps++; + if (c>0) + { + tempw = readmemw(ea_seg->base, SI); + if (abrt) break; +// pclog("OUTSW %04X -> %04X\n",SI,tempw); + outw(DX,tempw); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x16F: /*REP OUTSL*/ +// cpu_notreps++; + if (c > 0) + { + templ = readmeml(ea_seg->base, SI); + if (abrt) break; + outl(DX, templ); + if (flags & D_FLAG) SI -= 4; + else SI += 4; + c--; + cycles -= 14; + } + if (c > 0) { firstrepcycle = 0; cpu_state.pc = ipc; } + else firstrepcycle = 1; + break; + case 0x26F: /*REP OUTSW*/ +// cpu_notreps++; + if (c>0) + { + tempw = readmemw(ea_seg->base, ESI); + if (abrt) break; + outw(DX,tempw); + if (flags&D_FLAG) ESI-=2; + else ESI+=2; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x36F: /*REP OUTSL*/ +// cpu_notreps++; + if (c > 0) + { + templ = readmeml(ea_seg->base, ESI); + if (abrt) break; + outl(DX, templ); + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + c--; + cycles -= 14; + } + if (c > 0) { firstrepcycle = 0; cpu_state.pc = ipc; } + else firstrepcycle = 1; + break; + case 0x90: case 0x190: /*REP NOP*/ + case 0x290: case 0x390: +// cpu_notreps++; + break; + case 0xA4: case 0x1A4: /*REP MOVSB*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI); + temp2 = readmemb(ea_seg->base, SI); if (abrt) break; + writememb(es,DI,temp2); if (abrt) break; +// if (output==3) pclog("MOVSB %08X:%04X -> %08X:%04X %02X\n",ds,SI,es,DI,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2A4: case 0x3A4: /*REP MOVSB*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI); + temp2 = readmemb(ea_seg->base, ESI); if (abrt) break; + writememb(es,EDI,temp2); if (abrt) break; + if (flags&D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xA5: /*REP MOVSW*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI+1); + tempw = readmemw(ea_seg->base, SI); if (abrt) break; + writememw(es,DI,tempw); if (abrt) break; + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x1A5: /*REP MOVSL*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI+3); + templ = readmeml(ea_seg->base, SI); if (abrt) break; +// pclog("MOVSD %08X from %08X to %08X (%04X:%08X)\n", templ, ds+SI, es+DI, CS, pc); + writememl(es,DI,templ); if (abrt) break; + if (flags&D_FLAG) { DI-=4; SI-=4; } + else { DI+=4; SI+=4; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2A5: /*REP MOVSW*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI+1); + tempw = readmemw(ea_seg->base, ESI); if (abrt) break; + writememw(es,EDI,tempw); if (abrt) break; +// if (output) pclog("Written %04X from %08X to %08X %i %08X %04X %08X %04X\n",tempw,ds+ESI,es+EDI,c,ds,ES,es,ES); + if (flags&D_FLAG) { EDI-=2; ESI-=2; } + else { EDI+=2; ESI+=2; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x3A5: /*REP MOVSL*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI+3); + templ = readmeml(ea_seg->base, ESI); if (abrt) break; +// if ((EDI&0xFFFF0000)==0xA0000) cycles-=12; + writememl(es,EDI,templ); if (abrt) break; +// if (output) pclog("Load %08X from %08X to %08X %04X %08X %04X %08X\n",templ,ESI,EDI,DS,ds,ES,es); + if (flags&D_FLAG) { EDI-=4; ESI-=4; } + else { EDI+=4; ESI+=4; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xA6: case 0x1A6: /*REP CMPSB*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + temp = readmemb(ea_seg->base, SI); + temp2=readmemb(es,DI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=(is486)?7:9; + setsub8(temp,temp2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x2A6: case 0x3A6: /*REP CMPSB*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + temp = readmemb(ea_seg->base, ESI); + temp2=readmemb(es,EDI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + c--; + cycles-=(is486)?7:9; + setsub8(temp,temp2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0xA7: /*REP CMPSW*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { +// pclog("CMPSW (%04x:%04x)%05X (%04x:%04x)%05X ", DS,SI, ds+SI, ES,DI, es+DI); + tempw = readmemw(ea_seg->base, SI); + tempw2=readmemw(es,DI); +// pclog("%04X %04X %c%c %c%c\n", tempw, tempw2, tempw & 0xff, tempw >> 8, tempw2 & 0xff, tempw2 >> 8); + + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=(is486)?7:9; + setsub16(tempw,tempw2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x1A7: /*REP CMPSL*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + templ = readmeml(ea_seg->base, SI); + templ2=readmeml(es,DI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI-=4; SI-=4; } + else { DI+=4; SI+=4; } + c--; + cycles-=(is486)?7:9; + setsub32(templ,templ2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x2A7: /*REP CMPSW*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + tempw = readmemw(ea_seg->base, ESI); + tempw2=readmemw(es,EDI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { EDI-=2; ESI-=2; } + else { EDI+=2; ESI+=2; } + c--; + cycles-=(is486)?7:9; + setsub16(tempw,tempw2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x3A7: /*REP CMPSL*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + templ = readmeml(ea_seg->base, ESI); + templ2=readmeml(es,EDI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { EDI-=4; ESI-=4; } + else { EDI+=4; ESI+=4; } + c--; + cycles-=(is486)?7:9; + setsub32(templ,templ2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + + case 0xAA: case 0x1AA: /*REP STOSB*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI); + writememb(es,DI,AL); + if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2AA: case 0x3AA: /*REP STOSB*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI); + writememb(es,EDI,AL); + if (abrt) break; + if (flags&D_FLAG) EDI--; + else EDI++; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xAB: /*REP STOSW*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI+1); + writememw(es,DI,AX); + if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2AB: /*REP STOSW*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI+1); + writememw(es,EDI,AX); + if (abrt) break; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x1AB: /*REP STOSL*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI+3); + writememl(es,DI,EAX); + if (abrt) break; + if (flags&D_FLAG) DI-=4; + else DI+=4; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x3AB: /*REP STOSL*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI+3); + writememl(es,EDI,EAX); + if (abrt) break; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xAC: case 0x1AC: /*REP LODSB*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AL = readmemb(ea_seg->base, SI); + if (abrt) break; + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2AC: case 0x3AC: /*REP LODSB*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AL = readmemb(ea_seg->base, ESI); + if (abrt) break; + if (flags&D_FLAG) ESI--; + else ESI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AX = readmemw(ea_seg->base, SI); + if (abrt) break; + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x1AD: /*REP LODSL*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSL %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + EAX = readmeml(ea_seg->base, SI); + if (abrt) break; + if (flags&D_FLAG) SI-=4; + else SI+=4; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2AD: /*REP LODSW*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AX = readmemw(ea_seg->base, ESI); + if (abrt) break; + if (flags&D_FLAG) ESI-=2; + else ESI+=2; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x3AD: /*REP LODSL*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSL %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + EAX = readmeml(ea_seg->base, ESI); + if (abrt) break; + if (flags&D_FLAG) ESI-=4; + else ESI+=4; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xAE: case 0x1AE: /*REP SCASB*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); +// tempz=(fv)?1:0; + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + temp2=readmemb(es,DI); + if (abrt) { flags=of; break; } + setsub8(AL,temp2); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x2AE: case 0x3AE: /*REP SCASB*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); +// tempz=(fv)?1:0; + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + temp2=readmemb(es,EDI); + if (abrt) { flags=of; break; } +// if (output) pclog("Compare %02X,%02X\n",temp2,AL); + setsub8(AL,temp2); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) EDI--; + else EDI++; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0xAF: /*REP SCASW*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + tempw=readmemw(es,DI); + if (abrt) { flags=of; break; } + setsub16(AX,tempw); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x1AF: /*REP SCASL*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASL %04X(%06X):%06X\n",CS,cs,pc); + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + templ=readmeml(es,DI); + if (abrt) { flags=of; break; } + setsub32(EAX,templ); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) DI-=4; + else DI+=4; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x2AF: /*REP SCASW*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + tempw=readmemw(es,EDI); + if (abrt) { flags=of; break; } + setsub16(AX,tempw); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x3AF: /*REP SCASL*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASL %04X(%06X):%06X\n",CS,cs,pc); + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + templ=readmeml(es,EDI); + if (abrt) { flags=of; break; } + setsub32(EAX,templ); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + + + default: + cpu_state.pc = ipc+1; + //pclog("Bad REP %02X %i\n", temp, rep32 >> 8); + break; + } + if (rep32&0x200) ECX=c; + else CX=c; + CPU_BLOCK_END(); + return abrt; +//pclog("rep cpu_block_end=%d %p\n", cpu_block_end, (void *)&cpu_block_end); +// if (output) pclog("%03X %03X\n",rep32,use32); +} + +int checkio(int port) +{ + uint16_t t; + uint8_t d; + cpl_override = 1; + t = readmemw(tr.base, 0x66); + cpl_override = 0; +// pclog("CheckIO 1 %08X %04x %02x\n",tr.base, eflags, _cs.access); + if (abrt) return 0; +// pclog("CheckIO %04X %01X %01X %02X %04X %04X %08X ",CS,CPL,IOPL,port,t,t+(port>>3),tr.base+t+(port>>3)); + if ((t+(port>>3))>tr.limit) return 1; + cpl_override = 1; + // d = readmemb386l(0, tr.base + t + (port >> 3)); + d=readmemb(tr.base,t+(port>>3)); + cpl_override = 0; + if (d&(1<<(port&7))) pclog("%02X %02X %08X:%04X\n",d,d&(1<<(port&7)), tr.base, t); + if ((port & 0xfff8) == 0x1f0) + { + // if (d&(1<<(port&7))) fatal("Trying to read from IDE port %04X without permission\n", port); + } + return d&(1<<(port&7)); +} + +int xout=0; + + +#define divexcp() { \ + pclog("Divide exception at %04X(%06X):%04X\n",CS,cs,cpu_state.pc); \ + x86_int(0); \ +} + +int divl(uint32_t val) +{ + if (val==0) + { + divexcp(); + return 1; + } + uint64_t num=(((uint64_t)EDX)<<32)|EAX; + uint64_t quo=num/val; + uint32_t rem=num%val; + uint32_t quo32=(uint32_t)(quo&0xFFFFFFFF); + if (quo!=(uint64_t)quo32) + { + divexcp(); + return 1; + } + EDX=rem; + EAX=quo32; + return 0; +} +int idivl(int32_t val) +{ + if (val==0) + { + divexcp(); + return 1; + } + int64_t num=(((uint64_t)EDX)<<32)|EAX; + int64_t quo=num/val; + int32_t rem=num%val; + int32_t quo32=(int32_t)(quo&0xFFFFFFFF); + if (quo!=(int64_t)quo32) + { + divexcp(); + return 1; + } + EDX=rem; + EAX=quo32; + return 0; +} + + +void cpu_386_flags_extract() +{ + flags_extract(); +} +void cpu_386_flags_rebuild() +{ + flags_rebuild(); +} + +int oldi; + +uint32_t testr[9]; +int dontprint=0; + +#define OP_TABLE(name) ops_ ## name +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" + + +#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(flags & T_FLAG)) +//#define CACHE_ON() 0 + +static int cycles_main = 0; +void exec386_dynarec(int cycs) +{ + uint8_t temp; + uint32_t addr; + int tempi; + int cycdiff; + int oldcyc; + +//output = 3; + cycles_main += cycs; + while (cycles_main > 0) + { + int cycles_start; + + cycles += 1000; + cycles_start = cycles; + + timer_start_period(cycles << TIMER_SHIFT); +// output=3; + while (cycles>0) + { + oldcs = CS; + oldpc = cpu_state.pc; + oldcpl = CPL; + op32 = use32; + + + cycdiff=0; + oldcyc=cycles; +// if (output && CACHE_ON()) pclog("Block %04x:%04x %04x:%08x\n", CS, pc, SS,ESP); + if (!CACHE_ON()) /*Interpret block*/ + { + cpu_block_end = 0; +// if (output) pclog("Interpret block at %04x:%04x %04x %04x %04x %04x %04x %04x %04x\n", CS, pc, AX, BX, CX, DX, SI, DI, SP); + while (!cpu_block_end) + { + oldcs=CS; + oldpc=cpu_state.pc; + oldcpl=CPL; + op32=use32; + + ea_seg = &_ds; + ssegs = 0; + + opcodestart: + fetchdat = fastreadl(cs + cpu_state.pc); +// if (!fetchdat) +// fatal("Dead with cache off\n"); + if (!abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + +// if (output == 3) +// pclog("int %04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %f %02X%02X %02X%02X\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0x8f13f], ram[0x8f13e], ram[0x8f141], ram[0x8f140]); + + cpu_state.pc++; + x86_opcodes[(opcode | op32) & 0x3ff](fetchdat); + } + + if (!use32) cpu_state.pc &= 0xffff; + + if (((cs + cpu_state.pc) >> 12) != pccache) + CPU_BLOCK_END(); + +/* if (ssegs) + { + ds=oldds; + ss=oldss; + ssegs=0; + }*/ + if (abrt) + CPU_BLOCK_END(); + if (trap) + CPU_BLOCK_END(); + + ins++; + insc++; + +/* if ((cs + pc) == 4) + fatal("4\n");*/ +/* if (ins >= 141400000) + output = 3;*/ + } + } + else + { + uint32_t phys_addr = get_phys(cs+cpu_state.pc); + int hash = HASH(phys_addr); + codeblock_t *block = codeblock_hash[hash]; + int valid_block = 0; + trap = 0; + + if (block && !abrt) + { + page_t *page = &pages[phys_addr >> 12]; + + /*Block must match current CS, PC, code segment size, + and physical address. The physical address check will + also catch any page faults at this stage*/ + valid_block = (block->pc == cs + cpu_state.pc) && (block->_cs == cs) && + (block->use32 == use32) && (block->phys == phys_addr) && (block->stack32 == stack32); + if (!valid_block) + { + uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + if (page->code_present_mask & mask) + { + /*Walk page tree to see if we find the correct block*/ + codeblock_t *new_block = codeblock_tree_find(phys_addr); + if (new_block) + { + valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) && + (new_block->use32 == use32) && (new_block->phys == phys_addr) && (new_block->stack32 == stack32); + if (valid_block) + block = new_block; + } + } + } + if (valid_block && (block->page_mask & page->dirty_mask)) + { + codegen_check_flush(page, page->dirty_mask, phys_addr); + page->dirty_mask = 0; + if (!block->pc) + valid_block = 0; + } + if (valid_block && block->page_mask2) + { + /*We don't want the second page to cause a page + fault at this stage - that would break any + code crossing a page boundary where the first + page is present but the second isn't. Instead + allow the first page to be interpreted and for + the page fault to occur when the page boundary + is actually crossed.*/ + uint32_t phys_addr_2 = get_phys_noabrt(block->endpc) & ~0xfff; + page_t *page_2 = &pages[phys_addr_2 >> 12]; + + if ((block->phys_2 ^ phys_addr_2) & ~0xfff) + valid_block = 0; + else if (block->page_mask2 & page_2->dirty_mask) + { + codegen_check_flush(page_2, page_2->dirty_mask, phys_addr_2); + page_2->dirty_mask = 0; + if (!block->pc) + valid_block = 0; + } + } + } + + if (valid_block) + { + void (*code)() = (void *)&block->data[BLOCK_START]; + + codeblock_hash[hash] = block; +// if (output) pclog("Run block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%08x %04x %08x %08x %016llx %08x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, get_phys(cs+pc), block->phys, block->page_mask, block->endpc); + +inrecomp=1; + code(); +inrecomp=0; + if (!use32) cpu_state.pc &= 0xffff; +// cpu_recomp_ins += block->ins; + cpu_recomp_blocks++; +/* ins += codeblock_ins[index]; + insc += codeblock_ins[index];*/ +/* pclog("Exit block now %04X:%04X\n", CS, pc);*/ + } + else if (!abrt) + { + uint32_t start_page = cpu_state.pc >> 12; + uint32_t start_pc = cpu_state.pc; + +// pclog("Hash %08x %i\n", codeblock_hash_pc[HASH(cs + pc)], codeblock_page_dirty[(cs + pc) >> 12]); + cpu_block_end = 0; + x86_was_reset = 0; + + cpu_new_blocks++; + + codegen_block_init(phys_addr); + codegen_in_recompile = 1; + +// if (output) pclog("Recompile block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%04x %04x %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]); + while (!cpu_block_end) + { + oldcs=CS; + oldpc=cpu_state.pc; + oldcpl=CPL; + op32=use32; + + ea_seg = &_ds; + ssegs = 0; + + opcodestart_compile: + fetchdat = fastreadl(cs + cpu_state.pc); +// if (fetchdat == 0xffffffff) +// fatal("Dead ffffffff\n"); +// if (!fetchdat) +// fatal("Dead\n"); + if (!abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + +// if (output == 3) +// pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache); + + cpu_state.pc++; + + codegen_generate_call(opcode, x86_opcodes[(opcode | op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1); + + x86_opcodes[(opcode | op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + + if (!use32) cpu_state.pc &= 0xffff; + + /*Cap source code at 4000 bytes per block; this + will prevent any block from spanning more than + 2 pages. In practice this limit will never be + hit, as host block size is only 2kB*/ + if ((cpu_state.pc - start_pc) > 4000) + CPU_BLOCK_END(); + + if (trap) + CPU_BLOCK_END(); + + + if (abrt) + { + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + insc++; + } + + if (!abrt && !x86_was_reset) + codegen_block_end(); + + if (x86_was_reset) + codegen_reset(); + + codegen_in_recompile = 0; +// output &= ~2; + } +// if (output && (SP & 1)) +// fatal("odd SP\n"); + } + + cycdiff=oldcyc-cycles; + tsc += cycdiff; + +// timer_end_period(cycles); + + if (abrt) + { + flags_rebuild(); + tempi = abrt; + abrt = 0; + x86_doabrt(tempi); + if (abrt) + { + abrt = 0; + CS = oldcs; + cpu_state.pc = oldpc; + pclog("Double fault %i\n", ins); + pmodeint(8, 0); + if (abrt) + { + abrt = 0; + softresetx86(); + pclog("Triple fault - reset\n"); + } + } + } + + if (trap) + { + + flags_rebuild(); +// oldpc=pc; +// oldcs=CS; + if (msw&1) + { + pmodeint(1,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (1 << 2) + idt.base; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + else if ((flags&I_FLAG) && pic_intpending) + { + temp=picinterrupt(); + if (temp!=0xFF) + { +// pclog("IRQ %02X %04X:%04X %04X:%04X\n", temp, SS, SP, CS, pc); + CPU_BLOCK_END(); + flags_rebuild(); + if (msw&1) + { + pmodeint(temp,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr=temp<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + } + } + timer_end_period(cycles << TIMER_SHIFT); + cycles_main -= (cycles_start - cycles); + } +} diff --git a/src/386_dynarec_ops.c b/src/386_dynarec_ops.c new file mode 100644 index 000000000..bfa316488 --- /dev/null +++ b/src/386_dynarec_ops.c @@ -0,0 +1,57 @@ +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "x86_flags.h" +#include "mem.h" +#include "codegen.h" + +#define CPU_BLOCK_END() cpu_block_end = 1 + +#include "386_common.h" + + +extern uint16_t *mod1add[2][8]; +extern uint32_t *mod1seg[8]; + +static inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +static inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; if (mod != 3) fetch_ea_16_long(rmdat); +#define fetch_ea_32(rmdat) cpu_state.pc++; if (mod != 3) fetch_ea_32_long(rmdat); + + + +#define OP_TABLE(name) dynarec_ops_ ## name +#define CLOCK_CYCLES(c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" diff --git a/src/386_ops.h b/src/386_ops.h new file mode 100644 index 000000000..2aee7194c --- /dev/null +++ b/src/386_ops.h @@ -0,0 +1,1371 @@ +#include "x86_ops.h" + + +#define ILLEGAL_ON(cond) \ + do \ + { \ + if ((cond)) \ + { \ + cpu_state.pc = oldpc; \ + x86illegal(); \ + return 0; \ + } \ + } while (0) + +static inline void PUSH_W(uint16_t val) +{ + if (stack32) + { + writememw(ss, ESP - 2, val); if (abrt) return; + ESP -= 2; + } + else + { + writememw(ss, (SP - 2) & 0xFFFF, val); if (abrt) return; + SP -= 2; + } +} + +static inline void PUSH_L(uint32_t val) +{ + if (stack32) + { + writememl(ss, ESP - 4, val); if (abrt) return; + ESP -= 4; + } + else + { + writememl(ss, (SP - 4) & 0xFFFF, val); if (abrt) return; + SP -= 4; + } +} + +static inline uint16_t POP_W() +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(ss, ESP); if (abrt) return 0; + ESP += 2; + } + else + { + ret = readmemw(ss, SP); if (abrt) return 0; + SP += 2; + } + return ret; +} + +static inline uint32_t POP_L() +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(ss, ESP); if (abrt) return 0; + ESP += 4; + } + else + { + ret = readmeml(ss, SP); if (abrt) return 0; + SP += 4; + } + return ret; +} + +static inline uint16_t POP_W_seg(uint32_t seg) +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(seg, ESP); if (abrt) return 0; + ESP += 2; + } + else + { + ret = readmemw(seg, SP); if (abrt) return 0; + SP += 2; + } + return ret; +} + +static inline uint32_t POP_L_seg(uint32_t seg) +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(seg, ESP); if (abrt) return 0; + ESP += 4; + } + else + { + ret = readmeml(seg, SP); if (abrt) return 0; + SP += 4; + } + return ret; +} + +#include "x86seg.h" +#include "x86_ops_arith.h" +#include "x86_ops_atomic.h" +#include "x86_ops_bcd.h" +#include "x86_ops_bit.h" +#include "x86_ops_bitscan.h" +#include "x86_ops_call.h" +#include "x86_ops_flag.h" +#include "x86_ops_fpu.h" +#include "x86_ops_inc_dec.h" +#include "x86_ops_int.h" +#include "x86_ops_io.h" +#include "x86_ops_jump.h" +#include "x86_ops_misc.h" +#include "x86_ops_mmx.h" +#include "x86_ops_mmx_arith.h" +#include "x86_ops_mmx_cmp.h" +#include "x86_ops_mmx_logic.h" +#include "x86_ops_mmx_mov.h" +#include "x86_ops_mmx_pack.h" +#include "x86_ops_mmx_shift.h" +#include "x86_ops_mov.h" +#include "x86_ops_mov_ctrl.h" +#include "x86_ops_mov_seg.h" +#include "x86_ops_movx.h" +#include "x86_ops_msr.h" +#include "x86_ops_mul.h" +#include "x86_ops_pmode.h" +#include "x86_ops_prefix.h" +#include "x86_ops_rep.h" +#include "x86_ops_ret.h" +#include "x86_ops_set.h" +#include "x86_ops_shift.h" +#include "x86_ops_stack.h" +#include "x86_ops_string.h" +#include "x86_ops_xchg.h" + +static int ILLEGAL(uint32_t fetchdat) +{ + cpu_state.pc = oldpc; + +// fatal("Illegal instruction %08X\n", fetchdat); + pclog("Illegal instruction %08X\n", fetchdat); + x86illegal(); + return 0; +} + +static int op0F_w_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + cpu_state.pc++; + + // pclog("A16W: 0F %02X\n", opcode); + return x86_opcodes_0f[opcode](fetchdat >> 8); +} +static int op0F_l_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + cpu_state.pc++; + + // pclog("A16L: 0F %02X\n", opcode); + return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); +} +static int op0F_w_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + cpu_state.pc++; + + // pclog("A32W: 0F %02X\n", opcode); + return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); +} +static int op0F_l_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + cpu_state.pc++; + + // pclog("A32L: 0F %02X\n", opcode); + return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); +} + +#include "x87_ops.h" +#include "x86_ops_i686.h" + +OpFn OP_TABLE(286_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(386_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(486_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(winchip_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(pentium_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(pentiummmx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(k6_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(c6x86mx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(pentiumpro_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(pentium2_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(pentium2d_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,opFXSAVESTOR_a16,opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,opFXSAVESTOR_a16,opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,opFXSAVESTOR_a32,opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,opFXSAVESTOR_a32,opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(286)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +}; + +OpFn OP_TABLE(386)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, opFS_w_a16, opGS_w_a16, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_l_rmw_a16,opADD_b_rm_a16, opADD_l_rm_a16, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a16, opOR_l_rmw_a16, opOR_b_rm_a16, opOR_l_rm_a16, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a16, +/*10*/ opADC_b_rmw_a16,opADC_l_rmw_a16,opADC_b_rm_a16, opADC_l_rm_a16, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a16,opSBB_l_rmw_a16,opSBB_b_rm_a16, opSBB_l_rm_a16, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a16,opAND_l_rmw_a16,opAND_b_rm_a16, opAND_l_rm_a16, opAND_AL_imm, opAND_EAX_imm, opES_l_a16, opDAA, opSUB_b_rmw_a16,opSUB_l_rmw_a16,opSUB_b_rm_a16, opSUB_l_rm_a16, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_l_rmw_a16,opXOR_b_rm_a16, opXOR_l_rm_a16, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a16, opAAA, opCMP_b_rmw_a16,opCMP_l_rmw_a16,opCMP_b_rm_a16, opCMP_l_rm_a16, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a16, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a16, opARPL_a16, opFS_l_a16, opGS_l_a16, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a16,opPUSH_imm_bl, opIMUL_l_ib_a16,opINSB_a16, opINSL_a16, opOUTSB_a16, opOUTSL_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_l_a16, op80_a16, op83_l_a16, opTEST_b_a16, opTEST_l_a16, opXCHG_b_a16, opXCHG_l_a16, opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, opMOV_l_seg_a16,opLEA_l_a16, opMOV_seg_w_a16,opPOPL_a16, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_EAX_a16, opMOV_a16_AL, opMOV_a16_EAX, opMOVSB_a16, opMOVSL_a16, opCMPSB_a16, opCMPSL_a16, opTEST_AL, opTEST_EAX, opSTOSB_a16, opSTOSL_a16, opLODSB_a16, opLODSL_a16, opSCASB_a16, opSCASL_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a16, opC1_l_a16, opRET_l_imm, opRET_l, opLES_l_a16, opLDS_l_a16, opMOV_b_imm_a16,opMOV_l_imm_a16,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a16, opD1_l_a16, opD2_a16, opD3_l_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_l_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_l_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_w_rmw_a32,opADD_b_rm_a32, opADD_w_rm_a32, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a32, opOR_w_rmw_a32, opOR_b_rm_a32, opOR_w_rm_a32, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a32, +/*10*/ opADC_b_rmw_a32,opADC_w_rmw_a32,opADC_b_rm_a32, opADC_w_rm_a32, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a32,opSBB_w_rmw_a32,opSBB_b_rm_a32, opSBB_w_rm_a32, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a32,opAND_w_rmw_a32,opAND_b_rm_a32, opAND_w_rm_a32, opAND_AL_imm, opAND_AX_imm, opES_w_a32, opDAA, opSUB_b_rmw_a32,opSUB_w_rmw_a32,opSUB_b_rm_a32, opSUB_w_rm_a32, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_w_rmw_a32,opXOR_b_rm_a32, opXOR_w_rm_a32, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a32, opAAA, opCMP_b_rmw_a32,opCMP_w_rmw_a32,opCMP_b_rm_a32, opCMP_w_rm_a32, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a32, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a32, opARPL_a32, opFS_w_a32, opGS_w_a32, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a32,opPUSH_imm_bw, opIMUL_w_ib_a32,opINSB_a32, opINSW_a32, opOUTSB_a32, opOUTSW_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_w_a32, op80_a32, op83_w_a32, opTEST_b_a32, opTEST_w_a32, opXCHG_b_a32, opXCHG_w_a32, opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, opMOV_w_seg_a32,opLEA_w_a32, opMOV_seg_w_a32,opPOPW_a32, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_AX_a32, opMOV_a32_AL, opMOV_a32_AX, opMOVSB_a32, opMOVSW_a32, opCMPSB_a32, opCMPSW_a32, opTEST_AL, opTEST_AX, opSTOSB_a32, opSTOSW_a32, opLODSB_a32, opLODSW_a32, opSCASB_a32, opSCASW_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a32, opC1_w_a32, opRET_w_imm, opRET_w, opLES_w_a32, opLDS_w_a32, opMOV_b_imm_a32,opMOV_w_imm_a32,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a32, opD1_w_a32, opD2_a32, opD3_w_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_w_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_w_a32, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_l_rmw_a32,opADD_b_rm_a32, opADD_l_rm_a32, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a32, opOR_l_rmw_a32, opOR_b_rm_a32, opOR_l_rm_a32, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a32, +/*10*/ opADC_b_rmw_a32,opADC_l_rmw_a32,opADC_b_rm_a32, opADC_l_rm_a32, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a32,opSBB_l_rmw_a32,opSBB_b_rm_a32, opSBB_l_rm_a32, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a32,opAND_l_rmw_a32,opAND_b_rm_a32, opAND_l_rm_a32, opAND_AL_imm, opAND_EAX_imm, opES_l_a32, opDAA, opSUB_b_rmw_a32,opSUB_l_rmw_a32,opSUB_b_rm_a32, opSUB_l_rm_a32, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_l_rmw_a32,opXOR_b_rm_a32, opXOR_l_rm_a32, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a32, opAAA, opCMP_b_rmw_a32,opCMP_l_rmw_a32,opCMP_b_rm_a32, opCMP_l_rm_a32, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a32, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a32, opARPL_a32, opFS_l_a32, opGS_l_a32, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a32,opPUSH_imm_bl, opIMUL_l_ib_a32,opINSB_a32, opINSL_a32, opOUTSB_a32, opOUTSL_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_l_a32, op80_a32, op83_l_a32, opTEST_b_a32, opTEST_l_a32, opXCHG_b_a32, opXCHG_l_a32, opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, opMOV_l_seg_a32,opLEA_l_a32, opMOV_seg_w_a32,opPOPL_a32, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_EAX_a32, opMOV_a32_AL, opMOV_a32_EAX, opMOVSB_a32, opMOVSL_a32, opCMPSB_a32, opCMPSL_a32, opTEST_AL, opTEST_EAX, opSTOSB_a32, opSTOSL_a32, opLODSB_a32, opLODSL_a32, opSCASB_a32, opSCASL_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a32, opC1_l_a32, opRET_l_imm, opRET_l, opLES_l_a32, opLDS_l_a32, opMOV_b_imm_a32,opMOV_l_imm_a32,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a32, opD1_l_a32, opD2_a32, opD3_l_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, +}; diff --git a/src/808x.c b/src/808x.c new file mode 100644 index 000000000..4034e90dd --- /dev/null +++ b/src/808x.c @@ -0,0 +1,3509 @@ +//1B64 - Vid_SetMode (Vid_Vesa.c) +//6689c - CONS_Printf +/*SHR AX,1 + + 4 clocks - fetch opcode + 4 clocks - fetch mod/rm + 2 clocks - execute 2 clocks - fetch opcode 1 + 2 clocks - fetch opcode 2 + 4 clocks - fetch mod/rm + 2 clocks - fetch opcode 1 2 clocks - execute + 2 clocks - fetch opcode 2 etc*/ +#include +#include "ibm.h" + +#include "cpu.h" +#include "keyboard.h" +#include "mem.h" +#include "nmi.h" +#include "pic.h" +#include "timer.h" +#include "x86.h" + +int xt_cpu_multi; +int nmi = 0; + +int nextcyc=0; +int cycdiff; +int is8086=0; + +int memcycs; +int nopageerrors=0; + +void FETCHCOMPLETE(); + +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t seg, uint32_t addr); +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t seg, uint32_t addr); +void writememll(uint32_t seg, uint32_t addr, uint32_t val); + +#undef readmemb +#undef readmemw +uint8_t readmemb(uint32_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=4; + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint8_t readmembf(uint32_t a) +{ + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint16_t readmemw(uint32_t s, uint16_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=(8>>is8086); + if ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)) return readmemwl(s,a); + else return *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); +} + +void refreshread() { /*pclog("Refreshread\n"); */FETCHCOMPLETE(); memcycs+=4; } + +#undef fetchea +#define fetchea() { rmdat=FETCH(); \ + reg=(rmdat>>3)&7; \ + mod=(rmdat>>6)&3; \ + rm=rmdat&7; \ + if (mod!=3) fetcheal(); } + +void writemembl(uint32_t addr, uint8_t val); +void writememb(uint32_t a, uint8_t v) +{ + memcycs+=4; + if (writelookup2[(a)>>12]==-1) writemembl(a,v); + else *(uint8_t *)(writelookup2[a >> 12] + a) = v; +} +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +void writememw(uint32_t s, uint32_t a, uint16_t v) +{ + memcycs+=(8>>is8086); + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememwl(s,a,v); + else *(uint16_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} +void writememll(uint32_t seg, uint32_t addr, uint32_t val); +void writememl(uint32_t s, uint32_t a, uint32_t v) +{ + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememll(s,a,v); + else *(uint32_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} + + +void dumpregs(); +uint16_t oldcs; +int oldcpl; + +int tempc; +uint8_t opcode; +int times=0; +uint16_t pc2,pc3; +int noint=0; + +int output=0; + +int shadowbios=0; + +int ins=0; +//#define readmemb(a) (((a)<0xA0000)?ram[a]:readmembl(a)) + +int ssegs; + +int fetchcycles=0,memcycs,fetchclocks; + +uint8_t prefetchqueue[6]; +uint16_t prefetchpc; +int prefetchw=0; +inline uint8_t FETCH() +{ + uint8_t temp; +/* temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + if (prefetchw<=((is8086)?4:3)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + if (is8086 && (prefetchpc&1)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + } + }*/ + +// uint8_t temp=readmemb(cs+pc); +// if (output) printf("FETCH %04X %i\n",pc,fetchcycles); + if (prefetchw==0) //(fetchcycles<4) + { + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + fetchcycles=4; + temp=readmembf(cs+cpu_state.pc); + prefetchpc = cpu_state.pc = cpu_state.pc + 1; +// if (output) printf(" FETCH %04X:%04X %02X %04X %04X %i\n",CS,pc-1,temp,pc,prefetchpc,prefetchw); + if (is8086 && (cpu_state.pc&1)) + { + prefetchqueue[0]=readmembf(cs+cpu_state.pc); +// if (output) printf(" PREFETCHED from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + } + else + { + temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + prefetchw--; +// if (output) printf("PREFETCH %04X:%04X %02X %04X %04X %i\n",CS,pc,temp,pc,prefetchpc,prefetchw); + fetchcycles-=4; +// fetchclocks+=4; + cpu_state.pc++; + } +// if (output) printf("%i\n",fetchcycles); + return temp; +} + +inline void FETCHADD(int c) +{ + int d; +// if (output) printf("FETCHADD %i\n",c); + if (c<0) return; + if (prefetchw>((is8086)?4:3)) return; + d=c+(fetchcycles&3); + while (d>3 && prefetchw<((is8086)?6:4)) + { + d-=4; + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHED from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHED from %04X:%04X %02X\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + } + fetchcycles+=c; + if (fetchcycles>16) fetchcycles=16; +// if (fetchcycles>24) fetchcycles=24; +} + +void FETCHCOMPLETE() +{ +// pclog("Fetchcomplete %i %i %i\n",fetchcycles&3,fetchcycles,prefetchw); + if (!(fetchcycles&3)) return; + if (prefetchw>((is8086)?4:3)) return; + if (!prefetchw) nextcyc=(4-(fetchcycles&3)); + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHEDc from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHEDc from %04X:%04X %02X\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + fetchcycles+=(4-(fetchcycles&3)); +} + +inline void FETCHCLEAR() +{ +/* int c; + fetchcycles=0; + prefetchpc=pc; + if (is8086 && (prefetchpc&1)) cycles-=4; + for (c=0;c<((is8086)?6:4);c++) + { + prefetchqueue[c]=readmembf(cs+prefetchpc); + if (!is8086 || !(prefetchpc&1)) cycles-=4; + prefetchpc++; + } + prefetchw=(is8086)?6:4;*/ +// fetchcycles=0; + prefetchpc=cpu_state.pc; + prefetchw=0; + memcycs=cycdiff-cycles; + fetchclocks=0; +// memcycs=cycles; +/* prefetchqueue[0]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw=1; + if (is8086 && prefetchpc&1) + { + prefetchqueue[1]=readmembf(cs+prefetchpc); + prefetchpc++; + }*/ +} + +static uint16_t getword() +{ + uint8_t temp=FETCH(); + return temp|(FETCH()<<8); +} + + +/*EA calculation*/ + +/*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod + From 386 programmers manual : +r8(/r) AL CL DL BL AH CH DH BH +r16(/r) AX CX DX BX SP BP SI DI +r32(/r) EAX ECX EDX EBX ESP EBP ESI EDI +/digit (Opcode) 0 1 2 3 4 5 6 7 +REG = 000 001 010 011 100 101 110 111 + ÚÄÄÄAddress +disp8 denotes an 8-bit displacement following the ModR/M byte, to be +sign-extended and added to the index. disp16 denotes a 16-bit displacement +following the ModR/M byte, to be added to the index. Default segment +register is SS for the effective addresses containing a BP index, DS for +other effective addresses. + ÄÄ¿ ÚMod R/M¿ ÚÄÄÄÄÄÄÄÄModR/M Values in HexadecimalÄÄÄÄÄÄÄÄ¿ + +[BX + SI] 000 00 08 10 18 20 28 30 38 +[BX + DI] 001 01 09 11 19 21 29 31 39 +[BP + SI] 010 02 0A 12 1A 22 2A 32 3A +[BP + DI] 011 03 0B 13 1B 23 2B 33 3B +[SI] 00 100 04 0C 14 1C 24 2C 34 3C +[DI] 101 05 0D 15 1D 25 2D 35 3D +disp16 110 06 0E 16 1E 26 2E 36 3E +[BX] 111 07 0F 17 1F 27 2F 37 3F + +[BX+SI]+disp8 000 40 48 50 58 60 68 70 78 +[BX+DI]+disp8 001 41 49 51 59 61 69 71 79 +[BP+SI]+disp8 010 42 4A 52 5A 62 6A 72 7A +[BP+DI]+disp8 011 43 4B 53 5B 63 6B 73 7B +[SI]+disp8 01 100 44 4C 54 5C 64 6C 74 7C +[DI]+disp8 101 45 4D 55 5D 65 6D 75 7D +[BP]+disp8 110 46 4E 56 5E 66 6E 76 7E +[BX]+disp8 111 47 4F 57 5F 67 6F 77 7F + +[BX+SI]+disp16 000 80 88 90 98 A0 A8 B0 B8 +[BX+DI]+disp16 001 81 89 91 99 A1 A9 B1 B9 +[BX+SI]+disp16 010 82 8A 92 9A A2 AA B2 BA +[BX+DI]+disp16 011 83 8B 93 9B A3 AB B3 BB +[SI]+disp16 10 100 84 8C 94 9C A4 AC B4 BC +[DI]+disp16 101 85 8D 95 9D A5 AD B5 BD +[BP]+disp16 110 86 8E 96 9E A6 AE B6 BE +[BX]+disp16 111 87 8F 97 9F A7 AF B7 BF + +EAX/AX/AL 000 C0 C8 D0 D8 E0 E8 F0 F8 +ECX/CX/CL 001 C1 C9 D1 D9 E1 E9 F1 F9 +EDX/DX/DL 010 C2 CA D2 DA E2 EA F2 FA +EBX/BX/BL 011 C3 CB D3 DB E3 EB F3 FB +ESP/SP/AH 11 100 C4 CC D4 DC E4 EC F4 FC +EBP/BP/CH 101 C5 CD D5 DD E5 ED F5 FD +ESI/SI/DH 110 C6 CE D6 DE E6 EE F6 FE +EDI/DI/BH 111 C7 CF D7 DF E7 EF F7 FF + +mod = 11 - register + 10 - address + 16 bit displacement + 01 - address + 8 bit displacement + 00 - address + +reg = If mod=11, (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit registers) + 0=AX/AL 1=CX/CL 2=DX/DL 3=BX/BL + 4=SP/AH 5=BP/CH 6=SI/DH 7=DI/BH + + Otherwise, LSB selects SI/DI (0=SI), NMSB selects BX/BP (0=BX), and MSB + selects whether BX/BP are used at all (0=used). + + mod=00 is an exception though + 6=16 bit displacement only + 7=[BX] + + Usage varies with instructions. + + MOV AL,BL has ModR/M as C3, for example. + mod=11, reg=0, r/m=3 + MOV uses reg as dest, and r/m as src. + reg 0 is AL, reg 3 is BL + + If BP or SP are in address calc, seg is SS, else DS +*/ + +int cycles=0; +uint32_t easeg,eaaddr; +int rm,reg,mod,rmdat; + +uint16_t zero=0; +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +int slowrm[8]; + +void makemod1table() +{ + mod1add[0][0]=&BX; mod1add[0][1]=&BX; mod1add[0][2]=&BP; mod1add[0][3]=&BP; + mod1add[0][4]=&SI; mod1add[0][5]=&DI; mod1add[0][6]=&BP; mod1add[0][7]=&BX; + mod1add[1][0]=&SI; mod1add[1][1]=&DI; mod1add[1][2]=&SI; mod1add[1][3]=&DI; + mod1add[1][4]=&zero; mod1add[1][5]=&zero; mod1add[1][6]=&zero; mod1add[1][7]=&zero; + slowrm[0]=0; slowrm[1]=1; slowrm[2]=1; slowrm[3]=0; + mod1seg[0]=&ds; mod1seg[1]=&ds; mod1seg[2]=&ss; mod1seg[3]=&ss; + mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds; +} + +static void fetcheal() +{ + if (!mod && rm==6) { eaaddr=getword(); easeg=ds; FETCHADD(6); } + else + { + switch (mod) + { + case 0: + eaaddr=0; + if (rm&4) FETCHADD(5); + else FETCHADD(7+slowrm[rm]); + break; + case 1: + eaaddr=(uint16_t)(int8_t)FETCH(); + if (rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[rm]); + break; + case 2: + eaaddr=getword(); + if (rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[rm]); + break; + } + eaaddr+=(*mod1add[0][rm])+(*mod1add[1][rm]); + easeg=*mod1seg[rm]; + eaaddr&=0xFFFF; + } +} + +static inline uint8_t geteab() +{ + if (mod == 3) + return (rm & 4) ? cpu_state.regs[rm & 3].b.h : cpu_state.regs[rm & 3].b.l; + return readmemb(easeg+eaaddr); +} + +static inline uint16_t geteaw() +{ + if (mod == 3) + return cpu_state.regs[rm].w; +// if (output==3) printf("GETEAW %04X:%08X\n",easeg,eaaddr); + return readmemw(easeg,eaaddr); +} + +static inline uint16_t geteaw2() +{ + if (mod == 3) + return cpu_state.regs[rm].w; +// printf("Getting addr from %04X:%04X %05X\n",easeg,eaaddr+2,easeg+eaaddr+2); + return readmemw(easeg,(eaaddr+2)&0xFFFF); +} + +static inline void seteab(uint8_t val) +{ + if (mod == 3) + { + if (rm & 4) + cpu_state.regs[rm & 3].b.h = val; + else + cpu_state.regs[rm & 3].b.l = val; + } + else + { + writememb(easeg+eaaddr,val); + } +} + +static inline void seteaw(uint16_t val) +{ + if (mod == 3) + cpu_state.regs[rm].w = val; + else + { + writememw(easeg,eaaddr,val); +// writememb(easeg+eaaddr+1,val>>8); + } +} + +#define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) + +#define setr8(r,v) if (r & 4) cpu_state.regs[r & 3].b.h = v; \ + else cpu_state.regs[r & 3].b.l = v; + + +/*Flags*/ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +void makeznptable() +{ + int c,d; + for (c=0;c<256;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + znptable8[c]=0; + else + znptable8[c]=P_FLAG; + if (c == 0xb1) pclog("znp8 b1 = %i %02X\n", d, znptable8[c]); + if (!c) znptable8[c]|=Z_FLAG; + if (c&0x80) znptable8[c]|=N_FLAG; + } + for (c=0;c<65536;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + znptable16[c]=0; + else + znptable16[c]=P_FLAG; + if (c == 0xb1) pclog("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) pclog("znp16 65b1 = %i %02X\n", d, znptable16[c]); + if (!c) znptable16[c]|=Z_FLAG; + if (c&0x8000) znptable16[c]|=N_FLAG; + } + +// makemod1table(); +} +int timetolive=0; + +extern uint32_t oldcs2; +extern uint32_t oldpc2; + +int indump = 0; + +void dumpregs() +{ + int c,d=0,e=0,ff; +#ifndef RELEASE_BUILD + FILE *f; + if (indump) return; + indump = 1; +// return; + output=0; +// return; +// savenvr(); +// return; +chdir(pcempath); + nopageerrors=1; +/* f=fopen("rram3.dmp","wb"); + for (c=0;c<0x8000000;c++) putc(readmemb(c+0x10000000),f); + fclose(f);*/ + f=fopen("ram.dmp","wb"); + fwrite(ram,mem_size*1024,1,f); + fclose(f); +/* pclog("Dumping rram5.dmp\n"); + f=fopen("rram5.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c+0x10150000),f); + fclose(f);*/ + pclog("Dumping rram.dmp\n"); + f=fopen("rram.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c),f); + fclose(f); +/* f=fopen("rram2.dmp","wb"); + for (c=0;c<0x100000;c++) putc(readmemb(c+0xbff00000),f); + fclose(f); + f = fopen("stack.dmp","wb"); + for (c = 0; c < 0x6000; c++) putc(readmemb(c+0xFFDFA000), f); + fclose(f); + f = fopen("tempx.dmp","wb"); + for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFC816000), f); + fclose(f); + f = fopen("tempx2.dmp","wb"); + for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFDEF5000), f); + fclose(f);*/ + pclog("Dumping rram4.dmp\n"); + f=fopen("rram4.dmp","wb"); + for (c=0;c<0x0050000;c++) + { + abrt = 0; + putc(readmemb386l(0,c+0x80000000),f); + } + fclose(f); + pclog("Dumping done\n"); +/* f=fopen("rram6.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c+0xBF000000),f); + fclose(f);*/ +/* f=fopen("ram6.bin","wb"); + fwrite(ram+0x10100,0xA000,1,f); + fclose(f); + f=fopen("boot.bin","wb"); + fwrite(ram+0x7C00,0x200,1,f); + fclose(f); + f=fopen("ram7.bin","wb"); + fwrite(ram+0x11100,0x2000,1,f); + fclose(f); + f=fopen("ram8.bin","wb"); + fwrite(ram+0x3D210,0x200,1,f); + fclose(f); */ +/* f=fopen("bios.dmp","wb"); + fwrite(rom,0x20000,1,f); + fclose(f);*/ +/* f=fopen("kernel.dmp","wb"); + for (c=0;c<0x200000;c++) putc(readmemb(c+0xC0000000),f); + fclose(f);*/ +/* f=fopen("rram.dmp","wb"); + for (c=0;c<0x1500000;c++) putc(readmemb(c),f); + fclose(f); + if (!times) + { + f=fopen("thing.dmp","wb"); + fwrite(ram+0x11E50,0x1000,1,f); + fclose(f); + }*/ +#endif + if (is386) + printf("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n",EAX,EBX,ECX,EDX,EDI,ESI,EBP,ESP); + else + printf("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n",AX,BX,CX,DX,DI,SI,BP,SP); + printf("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,flags); + printf("%04X:%04X %04X:%04X\n",oldcs,oldpc, oldcs2, oldpc2); + printf("%i ins\n",ins); + if (is386) + printf("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + else + printf("In %s mode\n",(msw&1)?"protected":"real"); + printf("CS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",cs,_cs.limit,_cs.access, _cs.limit_low, _cs.limit_high); + printf("DS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ds,_ds.limit,_ds.access, _ds.limit_low, _ds.limit_high); + printf("ES : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",es,_es.limit,_es.access, _es.limit_low, _es.limit_high); + if (is386) + { + printf("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",seg_fs,_fs.limit,_fs.access, _fs.limit_low, _fs.limit_high); + printf("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",gs,_gs.limit,_gs.access, _gs.limit_low, _gs.limit_high); + } + printf("SS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ss,_ss.limit,_ss.access, _ss.limit_low, _ss.limit_high); + printf("GDT : base=%06X limit=%04X\n",gdt.base,gdt.limit); + printf("LDT : base=%06X limit=%04X\n",ldt.base,ldt.limit); + printf("IDT : base=%06X limit=%04X\n",idt.base,idt.limit); + printf("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + if (is386) + { + printf("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); + printf("CR0=%08X CR2=%08X CR3=%08X\n",cr0,cr2,cr3); + } + printf("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); + for (c=0;c<1024*1024;c++) + { + if (readlookup2[c]!=0xFFFFFFFF) d++; + if (writelookup2[c]!=0xFFFFFFFF) e++; + } + printf("Entries in readlookup : %i writelookup : %i\n",d,e); + x87_dumpregs(); + indump = 0; +} + +int resets = 0; +int x86_was_reset = 0; +void resetx86() +{ + pclog("x86 reset\n"); + resets++; + ins = 0; + use32=0; + stack32=0; +// i86_Reset(); +// cs=0xFFFF0; + cpu_state.pc=0; + msw=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cr4 = 0; + eflags=0; + cgate32=0; + loadcs(0xFFFF); + rammask=0xFFFFFFFF; + idt.base = 0; + flags=2; + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + FETCHCLEAR(); + x87_reset(); + cpu_set_edx(); + ESP=0; + mmu_perm=4; + memset(inscounts, 0, sizeof(inscounts)); + x86seg_reset(); + codegen_reset(); + x86_was_reset = 1; +} + +void softresetx86() +{ +// dumpregs(); +// exit(-1); + use32=0; + stack32=0; +// i86_Reset(); +// cs=0xFFFF0; + cpu_state.pc=0; + msw=0; + cr0=0; + cr4 = 0; + eflags=0; + cgate32=0; + loadcs(0xFFFF); + //rammask=0xFFFFFFFF; + flags=2; + idt.base = 0; + x86seg_reset(); + x86_was_reset = 1; +} + +static void setznp8(uint8_t val) +{ + flags&=~0xC4; + flags|=znptable8[val]; +} + +static void setznp16(uint16_t val) +{ + flags&=~0xC4; + flags|=znptable16[val]; +} + +static void setadd8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D4; + flags|=znptable16[c&0xFFFF]; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} + +static void setsub8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; +// if (output) printf("%04X %04X %i\n",a^b,a^c,flags&V_FLAG); + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D4; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + flags&=~0x8D5; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} + +int current_diff = 0; +void clockhardware() +{ + int diff = cycdiff - cycles - current_diff; + + current_diff += diff; + + timer_end_period(cycles*xt_cpu_multi); +} + +static int takeint = 0; + + +int firstrepcycle=1; + +void rep(int fv) +{ + uint8_t temp; + int c=CX; + uint8_t temp2; + uint16_t tempw,tempw2; + uint16_t ipc=oldpc;//pc-1; + int changeds=0; + uint32_t oldds; + startrep: + temp=FETCH(); + +// if (firstrepcycle && temp==0xA5) printf("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); +// if (output) printf("REP %02X %04X\n",temp,ipc); + switch (temp) + { + case 0x08: + cpu_state.pc=ipc+1; + cycles-=2; + FETCHCLEAR(); + break; + case 0x26: /*ES:*/ + oldds=ds; + ds=es; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x2E: /*CS:*/ + oldds=ds; + ds=cs; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x36: /*SS:*/ + oldds=ds; + ds=ss; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x6E: /*REP OUTSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xA4: /*REP MOVSB*/ + while (c>0 && !IRQTEST) + { + temp2=readmemb(ds+SI); + writememb(es+DI,temp2); +// if (output) printf("Moved %02X from %04X:%04X to %04X:%04X\n",temp2,ds>>4,SI,es>>4,DI); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17-memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// } + break; + case 0xA5: /*REP MOVSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// } + break; + case 0xA6: /*REP CMPSB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + temp=readmemb(ds+SI); + temp2=readmemb(es+DI); +// printf("CMPSB %c %c %i %05X %05X %04X:%04X\n",temp,temp2,c,ds+SI,es+DI,cs>>4,pc); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles -= 30; + setsub8(temp,temp2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; +// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; + break; + case 0xA7: /*REP CMPSW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + tempw2=readmemw(es,DI); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles -= 30; + setsub16(tempw,tempw2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; +// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// if (firstrepcycle) printf("REP CMPSW %06X:%04X %06X:%04X %04X %04X\n",ds,SI,es,DI,tempw,tempw2); + break; + case 0xAA: /*REP STOSB*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; + break; + case 0xAB: /*REP STOSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; + break; + case 0xAC: /*REP LODSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ + if (c>0) + { + tempw2=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAE: /*REP SCASB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp2=readmemb(es+DI); +// if (output) printf("SCASB %02X %c %02X %05X ",temp2,temp2,AL,es+DI); + setsub8(AL,temp2); +// if (output && flags&Z_FLAG) printf("Match %02X %02X\n",AL,temp2); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 15; + } +//if (output) printf("%i %i %i %i\n",c,(c>0),(fv==((flags&Z_FLAG)?1:0)),((c>0) && (fv==((flags&Z_FLAG)?1:0)))); + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; +// cycles-=120; + break; + case 0xAF: /*REP SCASW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 15; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + default: + cpu_state.pc = ipc+1; + cycles-=20; + FETCHCLEAR(); +// printf("Bad REP %02X\n",temp); +// dumpregs(); +// exit(-1); + } + CX=c; + if (changeds) ds=oldds; + if (IRQTEST) + takeint = 1; +// if (pc==ipc) FETCHCLEAR(); +} + + +int inhlt=0; +uint16_t lastpc,lastcs; +int firstrepcycle; +int skipnextprint=0; + +int instime=0; +//#if 0 +void execx86(int cycs) +{ + uint8_t temp,temp2; + uint16_t addr,tempw,tempw2,tempw3,tempw4; + int8_t offset; + int tempws; + uint32_t templ; + int c; + int tempi; + int trap; + +// printf("Run x86! %i %i\n",cycles,cycs); + cycles+=cycs; +// i86_Execute(cycs); +// return; + while (cycles>0) + { +// old83=old82; +// old82=old8; +// old8=oldpc|(oldcs<<16); +// if (pc==0x96B && cs==0x9E040) { printf("Hit it\n"); output=1; timetolive=150; } +// if (pc<0x8000) printf("%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i\n",pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags,disctime); + cycdiff=cycles; + timer_start_period(cycles*xt_cpu_multi); + current_diff = 0; + cycles-=nextcyc; +// if (instime) pclog("Cycles %i %i\n",cycles,cycdiff); + nextcyc=0; +// if (output) printf("CLOCK %i %i\n",cycdiff,cycles); + fetchclocks=0; + oldcs=CS; + oldpc=cpu_state.pc; + opcodestart: + opcode=FETCH(); + tempc=flags&C_FLAG; + trap=flags&T_FLAG; + cpu_state.pc--; +// output=1; +// if (output) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X\n",cs>>4,pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags&~0x200,rmdat); +//#if 0 + if (output) + { +// if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) +// { + if (!skipnextprint) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i %p %02X\n",cs,cpu_state.pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ins, ram, ram[0x1a925]); + skipnextprint=0; +// ins++; +// } + } +//#endif + cpu_state.pc++; + inhlt=0; +// if (ins==500000) { dumpregs(); exit(0); }*/ + switch (opcode) + { + case 0x00: /*ADD 8,reg*/ + fetchea(); +/* if (!rmdat) pc--; + if (!rmdat) + { + fatal("Crashed\n"); +// clear_keybuf(); +// readkey(); + }*/ + temp=geteab(); + setadd8(temp,getr8(reg)); + temp+=getr8(reg); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x01: /*ADD 16,reg*/ + fetchea(); + tempw=geteaw(); + setadd16(tempw, cpu_state.regs[reg].w); + tempw += cpu_state.regs[reg].w; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x02: /*ADD reg,8*/ + fetchea(); + temp=geteab(); + setadd8(getr8(reg),temp); + setr8(reg,getr8(reg)+temp); + cycles-=((mod==3)?3:13); + break; + case 0x03: /*ADD reg,16*/ + fetchea(); + tempw=geteaw(); + setadd16(cpu_state.regs[reg].w,tempw); + cpu_state.regs[reg].w+=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x04: /*ADD AL,#8*/ + temp=FETCH(); + setadd8(AL,temp); + AL+=temp; + cycles-=4; + break; + case 0x05: /*ADD AX,#16*/ + tempw=getword(); + setadd16(AX,tempw); + AX+=tempw; + cycles-=4; + break; + + case 0x06: /*PUSH ES*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),ES); + SP-=2; + cycles-=14; + break; + case 0x07: /*POP ES*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_es); + SP+=2; + cycles-=12; + break; + + case 0x08: /*OR 8,reg*/ + fetchea(); + temp=geteab(); + temp|=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x09: /*OR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x0A: /*OR reg,8*/ + fetchea(); + temp=geteab(); + temp|=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(reg,temp); + cycles-=((mod==3)?3:13); + break; + case 0x0B: /*OR reg,16*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x0C: /*OR AL,#8*/ + AL|=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x0D: /*OR AX,#16*/ + AX|=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x0E: /*PUSH CS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),CS); + SP-=2; + cycles-=14; + break; + case 0x0F: /*POP CS - 8088/8086 only*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_cs); + SP+=2; + cycles-=12; + break; + + case 0x10: /*ADC 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(reg); + setadc8(temp,temp2); + temp+=temp2+tempc; + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x11: /*ADC 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[reg].w; + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x12: /*ADC reg,8*/ + fetchea(); + temp=geteab(); + setadc8(getr8(reg),temp); + setr8(reg,getr8(reg)+temp+tempc); + cycles-=((mod==3)?3:13); + break; + case 0x13: /*ADC reg,16*/ + fetchea(); + tempw=geteaw(); + setadc16(cpu_state.regs[reg].w,tempw); + cpu_state.regs[reg].w+=tempw+tempc; + cycles-=((mod==3)?3:13); + break; + case 0x14: /*ADC AL,#8*/ + tempw=FETCH(); + setadc8(AL,tempw); + AL+=tempw+tempc; + cycles-=4; + break; + case 0x15: /*ADC AX,#16*/ + tempw=getword(); + setadc16(AX,tempw); + AX+=tempw+tempc; + cycles-=4; + break; + + case 0x16: /*PUSH SS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),SS); + SP-=2; + cycles-=14; + break; + case 0x17: /*POP SS*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ss); + SP+=2; + noint=1; + cycles-=12; +// output=1; + break; + + case 0x18: /*SBB 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(reg); + setsbc8(temp,temp2); + temp-=(temp2+tempc); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x19: /*SBB 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[reg].w; +// printf("%04X:%04X SBB %04X-%04X,%i\n",cs>>4,pc,tempw,tempw2,tempc); + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x1A: /*SBB reg,8*/ + fetchea(); + temp=geteab(); + setsbc8(getr8(reg),temp); + setr8(reg,getr8(reg)-(temp+tempc)); + cycles-=((mod==3)?3:13); + break; + case 0x1B: /*SBB reg,16*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[reg].w; +// printf("%04X:%04X SBB %04X-%04X,%i\n",cs>>4,pc,tempw,tempw2,tempc); + setsbc16(tempw2,tempw); + tempw2-=(tempw+tempc); + cpu_state.regs[reg].w=tempw2; + cycles-=((mod==3)?3:13); + break; + case 0x1C: /*SBB AL,#8*/ + temp=FETCH(); + setsbc8(AL,temp); + AL-=(temp+tempc); + cycles-=4; + break; + case 0x1D: /*SBB AX,#16*/ + tempw=getword(); + setsbc16(AX,tempw); + AX-=(tempw+tempc); + cycles-=4; + break; + + case 0x1E: /*PUSH DS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),DS); + SP-=2; + cycles-=14; + break; + case 0x1F: /*POP DS*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + SP+=2; + cycles-=12; + break; + + case 0x20: /*AND 8,reg*/ + fetchea(); + temp=geteab(); + temp&=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x21: /*AND 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x22: /*AND reg,8*/ + fetchea(); + temp=geteab(); + temp&=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(reg,temp); + cycles-=((mod==3)?3:13); + break; + case 0x23: /*AND reg,16*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x24: /*AND AL,#8*/ + AL&=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x25: /*AND AX,#16*/ + AX&=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x26: /*ES:*/ + oldss=ss; + oldds=ds; + ds=ss=es; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x27: /*DAA*/ + if ((flags&A_FLAG) || ((AL&0xF)>9)) + { + tempi=((uint16_t)AL)+6; + AL+=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } +// else +// flags&=~A_FLAG; + if ((flags&C_FLAG) || (AL>0x9F)) + { + AL+=0x60; + flags|=C_FLAG; + } +// else +// flags&=~C_FLAG; + setznp8(AL); + cycles-=4; + break; + + case 0x28: /*SUB 8,reg*/ + fetchea(); + temp=geteab(); + setsub8(temp,getr8(reg)); + temp-=getr8(reg); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x29: /*SUB 16,reg*/ + fetchea(); + tempw=geteaw(); +// printf("%04X:%04X %04X-%04X\n",cs>>4,pc,tempw,cpu_state.regs[reg].w); + setsub16(tempw,cpu_state.regs[reg].w); + tempw-=cpu_state.regs[reg].w; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x2A: /*SUB reg,8*/ + fetchea(); + temp=geteab(); + setsub8(getr8(reg),temp); + setr8(reg,getr8(reg)-temp); + cycles-=((mod==3)?3:13); + break; + case 0x2B: /*SUB reg,16*/ + fetchea(); + tempw=geteaw(); +// printf("%04X:%04X %04X-%04X\n",cs>>4,pc,cpu_state.regs[reg].w,tempw); + setsub16(cpu_state.regs[reg].w,tempw); + cpu_state.regs[reg].w-=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x2C: /*SUB AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + AL-=temp; + cycles-=4; + break; + case 0x2D: /*SUB AX,#16*/ +// printf("INS %i\n",ins); +// output=1; + tempw=getword(); + setsub16(AX,tempw); + AX-=tempw; + cycles-=4; + break; + case 0x2E: /*CS:*/ + oldss=ss; + oldds=ds; + ds=ss=cs; + ssegs=2; + cycles-=4; + goto opcodestart; + case 0x2F: /*DAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + tempi=((uint16_t)AL)-6; + AL-=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } +// else +// flags&=~A_FLAG; + if ((flags&C_FLAG)||(AL>0x9F)) + { + AL-=0x60; + flags|=C_FLAG; + } +// else +// flags&=~C_FLAG; + setznp8(AL); + cycles-=4; + break; + case 0x30: /*XOR 8,reg*/ + fetchea(); + temp=geteab(); + temp^=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x31: /*XOR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x32: /*XOR reg,8*/ + fetchea(); + temp=geteab(); + temp^=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(reg,temp); + cycles-=((mod==3)?3:13); + break; + case 0x33: /*XOR reg,16*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x34: /*XOR AL,#8*/ + AL^=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x35: /*XOR AX,#16*/ + AX^=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x36: /*SS:*/ + oldss=ss; + oldds=ds; + ds=ss=ss; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x37: /*AAA*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL+=6; + AH++; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x38: /*CMP 8,reg*/ + fetchea(); + temp=geteab(); +// if (output) printf("CMP %02X-%02X\n",temp,getr8(reg)); + setsub8(temp,getr8(reg)); + cycles-=((mod==3)?3:13); + break; + case 0x39: /*CMP 16,reg*/ + fetchea(); + tempw=geteaw(); +// if (output) printf("CMP %04X-%04X\n",tempw,cpu_state.regs[reg].w); + setsub16(tempw,cpu_state.regs[reg].w); + cycles-=((mod==3)?3:13); + break; + case 0x3A: /*CMP reg,8*/ + fetchea(); + temp=geteab(); +// if (output) printf("CMP %02X-%02X\n",getr8(reg),temp); + setsub8(getr8(reg),temp); + cycles-=((mod==3)?3:13); + break; + case 0x3B: /*CMP reg,16*/ + fetchea(); + tempw=geteaw(); +// printf("CMP %04X-%04X\n",cpu_state.regs[reg].w,tempw); + setsub16(cpu_state.regs[reg].w,tempw); + cycles-=((mod==3)?3:13); + break; + case 0x3C: /*CMP AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + cycles-=4; + break; + case 0x3D: /*CMP AX,#16*/ + tempw=getword(); + setsub16(AX,tempw); + cycles-=4; + break; + + case 0x3E: /*DS:*/ + oldss=ss; + oldds=ds; + ds=ss=ds; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x3F: /*AAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL-=6; + AH--; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x44: case 0x45: case 0x46: case 0x47: + setadd16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w++; + cycles-=3; + break; + case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + setsub16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w--; + cycles-=3; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + if (ssegs) ss=oldss; + SP-=2; + writememw(ss,SP,cpu_state.regs[opcode&7].w); + cycles-=15; + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + if (ssegs) ss=oldss; + SP+=2; + cpu_state.regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); + cycles-=12; + break; + + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + offset=(int8_t)FETCH(); + if (flags&V_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + offset=(int8_t)FETCH(); + if (!(flags&V_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + offset=(int8_t)FETCH(); + if (flags&C_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + offset=(int8_t)FETCH(); + if (!(flags&C_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + offset=(int8_t)FETCH(); + if (flags&Z_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + offset=(int8_t)FETCH(); + cycles-=4; + if (!(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + offset=(int8_t)FETCH(); + if (flags&(C_FLAG|Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + offset=(int8_t)FETCH(); + if (!(flags&(C_FLAG|Z_FLAG))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + offset=(int8_t)FETCH(); + if (flags&N_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + offset=(int8_t)FETCH(); + if (!(flags&N_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + offset=(int8_t)FETCH(); + if (flags&P_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + offset=(int8_t)FETCH(); + if (!(flags&P_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + + case 0x80: case 0x82: + fetchea(); + temp=geteab(); + temp2=FETCH(); + switch (rmdat&0x38) + { + case 0x00: /*ADD b,#8*/ + setadd8(temp,temp2); + seteab(temp+temp2); + cycles-=((mod==3)?4:23); + break; + case 0x08: /*OR b,#8*/ + temp|=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?4:23); + break; + case 0x10: /*ADC b,#8*/ +// temp2+=(flags&C_FLAG); + setadc8(temp,temp2); + seteab(temp+temp2+tempc); + cycles-=((mod==3)?4:23); + break; + case 0x18: /*SBB b,#8*/ +// temp2+=(flags&C_FLAG); + setsbc8(temp,temp2); + seteab(temp-(temp2+tempc)); + cycles-=((mod==3)?4:23); + break; + case 0x20: /*AND b,#8*/ + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?4:23); + break; + case 0x28: /*SUB b,#8*/ + setsub8(temp,temp2); + seteab(temp-temp2); + cycles-=((mod==3)?4:23); + break; + case 0x30: /*XOR b,#8*/ + temp^=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?4:23); + break; + case 0x38: /*CMP b,#8*/ + setsub8(temp,temp2); + cycles-=((mod==3)?4:14); + break; + +// default: +// printf("Bad 80 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x81: + fetchea(); + tempw=geteaw(); + tempw2=getword(); + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#16*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x08: /*OR w,#16*/ + tempw|=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x10: /*ADC w,#16*/ +// tempw2+=(flags&C_FLAG); + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x20: /*AND w,#16*/ + tempw&=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x18: /*SBB w,#16*/ +// tempw2+=(flags&C_FLAG); + setsbc16(tempw,tempw2); + seteaw(tempw-(tempw2+tempc)); + cycles-=((mod==3)?4:23); + break; + case 0x28: /*SUB w,#16*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x30: /*XOR w,#16*/ + tempw^=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x38: /*CMP w,#16*/ +// printf("CMP %04X %04X\n",tempw,tempw2); + setsub16(tempw,tempw2); + cycles-=((mod==3)?4:14); + break; + +// default: +// printf("Bad 81 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x83: + fetchea(); + tempw=geteaw(); + tempw2=FETCH(); + if (tempw2&0x80) tempw2|=0xFF00; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#8*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x08: /*OR w,#8*/ + tempw|=tempw2; + setznp16(tempw); + seteaw(tempw); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + cycles-=((mod==3)?4:23); + break; + case 0x10: /*ADC w,#8*/ +// tempw2+=(flags&C_FLAG); + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x18: /*SBB w,#8*/ +// tempw2+=(flags&C_FLAG); + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x20: /*AND w,#8*/ + tempw&=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x28: /*SUB w,#8*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x30: /*XOR w,#8*/ + tempw^=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x38: /*CMP w,#8*/ + setsub16(tempw,tempw2); + cycles-=((mod==3)?4:14); + break; + +// default: +// printf("Bad 83 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x84: /*TEST b,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(reg); + setznp8(temp&temp2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?3:13); + break; + case 0x85: /*TEST w,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[reg].w; + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?3:13); + break; + case 0x86: /*XCHG b,reg*/ + fetchea(); + temp=geteab(); + seteab(getr8(reg)); + setr8(reg,temp); + cycles-=((mod==3)?4:25); + break; + case 0x87: /*XCHG w,reg*/ + fetchea(); + tempw=geteaw(); + seteaw(cpu_state.regs[reg].w); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?4:25); + break; + + case 0x88: /*MOV b,reg*/ + fetchea(); + seteab(getr8(reg)); + cycles-=((mod==3)?2:13); + break; + case 0x89: /*MOV w,reg*/ + fetchea(); + seteaw(cpu_state.regs[reg].w); + cycles-=((mod==3)?2:13); + break; + case 0x8A: /*MOV reg,b*/ + fetchea(); + temp=geteab(); + setr8(reg,temp); + cycles-=((mod==3)?2:12); + break; + case 0x8B: /*MOV reg,w*/ + fetchea(); + tempw=geteaw(); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?2:12); + break; + + case 0x8C: /*MOV w,sreg*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds=oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss=oldss; + seteaw(SS); + break; + } + cycles-=((mod==3)?2:13); + break; + + case 0x8D: /*LEA*/ + fetchea(); + cpu_state.regs[reg].w=eaaddr; + cycles-=2; + break; + + case 0x8E: /*MOV sreg,w*/ +// if (output) printf("MOV %04X ",pc); + fetchea(); +// if (output) printf("%04X %02X\n",pc,rmdat); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + tempw=geteaw(); + loadseg(tempw,&_es); + break; + case 0x08: /*CS - 8088/8086 only*/ + tempw=geteaw(); + loadseg(tempw,&_cs); + break; + case 0x18: /*DS*/ + tempw=geteaw(); + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + break; + case 0x10: /*SS*/ + tempw=geteaw(); + loadseg(tempw,&_ss); + if (ssegs) oldss=ss; +// printf("LOAD SS %04X %04X\n",tempw,SS); +// printf("SS loaded with %04X %04X:%04X %04X %04X %04X\n",ss>>4,cs>>4,pc,CX,DX,es>>4); + break; + } + cycles-=((mod==3)?2:12); + skipnextprint=1; + noint=1; + break; + + case 0x8F: /*POPW*/ + fetchea(); + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + SP+=2; + seteaw(tempw); + cycles-=25; + break; + + case 0x90: /*NOP*/ + cycles-=3; + break; + + case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x94: case 0x95: case 0x96: case 0x97: + tempw=AX; + AX=cpu_state.regs[opcode&7].w; + cpu_state.regs[opcode&7].w=tempw; + cycles-=3; + break; + + case 0x98: /*CBW*/ + AH=(AL&0x80)?0xFF:0; + cycles-=2; + break; + case 0x99: /*CWD*/ + DX=(AX&0x8000)?0xFFFF:0; + cycles-=5; + break; + case 0x9A: /*CALL FAR*/ + tempw=getword(); + tempw2=getword(); + tempw3=CS; + tempw4=cpu_state.pc; + if (ssegs) ss=oldss; + cpu_state.pc=tempw; +// printf("0x9a"); + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,(SP-4)&0xFFFF,tempw4); + SP-=4; + cycles-=36; + FETCHCLEAR(); + break; + case 0x9B: /*WAIT*/ + cycles-=4; + break; + case 0x9C: /*PUSHF*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + SP-=2; + cycles-=14; + break; + case 0x9D: /*POPF*/ + if (ssegs) ss=oldss; + flags=readmemw(ss,SP)&0xFFF; + SP+=2; + cycles-=12; + break; + case 0x9E: /*SAHF*/ + flags=(flags&0xFF00)|AH; + cycles-=4; + break; + case 0x9F: /*LAHF*/ + AH=flags&0xFF; + cycles-=4; + break; + + case 0xA0: /*MOV AL,(w)*/ + addr=getword(); + AL=readmemb(ds+addr); + cycles-=14; + break; + case 0xA1: /*MOV AX,(w)*/ + addr=getword(); +// printf("Reading AX from %05X %04X:%04X\n",ds+addr,ds>>4,addr); + AX=readmemw(ds,addr); + cycles-=!4; + break; + case 0xA2: /*MOV (w),AL*/ + addr=getword(); + writememb(ds+addr,AL); + cycles-=14; + break; + case 0xA3: /*MOV (w),AX*/ + addr=getword(); +// if (!addr) printf("Write !addr %04X:%04X\n",cs>>4,pc); + writememw(ds,addr,AX); + cycles-=14; + break; + + case 0xA4: /*MOVSB*/ + temp=readmemb(ds+SI); + writememb(es+DI,temp); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=18; + break; + case 0xA5: /*MOVSW*/ + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=18; + break; + case 0xA6: /*CMPSB*/ + temp =readmemb(ds+SI); + temp2=readmemb(es+DI); + setsub8(temp,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=30; + break; + case 0xA7: /*CMPSW*/ + tempw =readmemw(ds,SI); + tempw2=readmemw(es,DI); +// printf("CMPSW %04X %04X\n",tempw,tempw2); + setsub16(tempw,tempw2); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=30; + break; + case 0xA8: /*TEST AL,#8*/ + temp=FETCH(); + setznp8(AL&temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xA9: /*TEST AX,#16*/ + tempw=getword(); + setznp16(AX&tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xAA: /*STOSB*/ + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=11; + break; + case 0xAB: /*STOSW*/ + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=11; + break; + case 0xAC: /*LODSB*/ + AL=readmemb(ds+SI); +// printf("LODSB %04X:%04X %02X %04X:%04X\n",cs>>4,pc,AL,ds>>4,SI); + if (flags&D_FLAG) SI--; + else SI++; + cycles-=16; + break; + case 0xAD: /*LODSW*/ +// if (times) printf("LODSW %04X:%04X\n",cs>>4,pc); + AX=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + cycles-=16; + break; + case 0xAE: /*SCASB*/ + temp=readmemb(es+DI); + setsub8(AL,temp); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=19; + break; + case 0xAF: /*SCASW*/ + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=19; + break; + + case 0xB0: /*MOV AL,#8*/ + AL=FETCH(); + cycles-=4; + break; + case 0xB1: /*MOV CL,#8*/ + CL=FETCH(); + cycles-=4; + break; + case 0xB2: /*MOV DL,#8*/ + DL=FETCH(); + cycles-=4; + break; + case 0xB3: /*MOV BL,#8*/ + BL=FETCH(); + cycles-=4; + break; + case 0xB4: /*MOV AH,#8*/ + AH=FETCH(); + cycles-=4; + break; + case 0xB5: /*MOV CH,#8*/ + CH=FETCH(); + cycles-=4; + break; + case 0xB6: /*MOV DH,#8*/ + DH=FETCH(); + cycles-=4; + break; + case 0xB7: /*MOV BH,#8*/ + BH=FETCH(); + cycles-=4; + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + cpu_state.regs[opcode&7].w=getword(); + cycles-=4; + break; + + case 0xC0: /*RET alias*/ + case 0xC2: /*RET*/ + tempw=getword(); + if (ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); +// printf("C2\n"); +// printf("RET to %04X\n",pc); + SP+=2+tempw; + cycles-=24; + FETCHCLEAR(); + break; + case 0xC1: /*RET alias*/ + case 0xC3: /*RET*/ + if (ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); +// printf("C3\n"); +// if (output) printf("RET to %04X %05X\n",pc,ss+SP); + SP+=2; + cycles-=20; + FETCHCLEAR(); + break; + case 0xC4: /*LES*/ + fetchea(); + cpu_state.regs[reg].w=readmemw(easeg,eaaddr); //geteaw(); + tempw=readmemw(easeg,(eaaddr+2)&0xFFFF); //geteaw2(); + loadseg(tempw,&_es); + cycles-=24; + break; + case 0xC5: /*LDS*/ + fetchea(); + cpu_state.regs[reg].w=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,(eaaddr+2)&0xFFFF); + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + cycles-=24; + break; + case 0xC6: /*MOV b,#8*/ + fetchea(); + temp=FETCH(); + seteab(temp); + cycles-=((mod==3)?4:14); + break; + case 0xC7: /*MOV w,#16*/ + fetchea(); + tempw=getword(); + seteaw(tempw); + cycles-=((mod==3)?4:14); + break; + + case 0xC8: /*RETF alias*/ + case 0xCA: /*RETF*/ + tempw=getword(); + if (ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); +// printf("CA\n"); + loadcs(readmemw(ss,SP+2)); + SP+=4; + SP+=tempw; + cycles-=33; + FETCHCLEAR(); + break; + case 0xC9: /*RETF alias*/ + case 0xCB: /*RETF*/ + if (ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); +// printf("CB\n"); + loadcs(readmemw(ss,SP+2)); + SP+=4; + cycles-=34; + FETCHCLEAR(); + break; + case 0xCC: /*INT 3*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + addr=3<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; +// printf("CC %04X:%04X ",CS,pc); + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); +// printf("%04X:%04X\n",CS,pc); + cycles-=72; + break; + case 0xCD: /*INT*/ + lastpc=cpu_state.pc; + lastcs=CS; + temp=FETCH(); + + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + flags&=~T_FLAG; + SP-=6; + addr=temp<<2; + cpu_state.pc=readmemw(0,addr); + + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); + + cycles-=71; + break; + case 0xCF: /*IRET*/ + if (ssegs) ss=oldss; + tempw=CS; + tempw2=cpu_state.pc; + cpu_state.pc=readmemw(ss,SP); +// printf("CF\n"); + loadcs(readmemw(ss,((SP+2)&0xFFFF))); + flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; + SP+=6; + cycles-=44; + FETCHCLEAR(); + nmi_enable = 1; + break; + case 0xD0: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (flags&C_FLAG) temp|=1; + seteab(temp); +// setznp8(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x08: /*ROR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (flags&C_FLAG) temp|=0x80; + seteab(temp); +// setznp8(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x10: /*RCL b,1*/ + temp2=flags&C_FLAG; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (temp2) temp|=1; + seteab(temp); +// setznp8(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x18: /*RCR b,1*/ + temp2=flags&C_FLAG; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp2) temp|=0x80; + seteab(temp); +// setznp8(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((temp^(temp<<1))&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp<<=1; + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (temp&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp>>=1; + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp&0x40) temp|=0x80; + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + +// default: +// printf("Bad D0 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD1: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*ROL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (flags&C_FLAG) tempw|=1; + seteaw(tempw); +// setznp16(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x08: /*ROR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (flags&C_FLAG) tempw|=0x8000; + seteaw(tempw); +// setznp16(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x10: /*RCL w,1*/ + temp2=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (temp2) tempw|=1; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x18: /*RCR w,1*/ + temp2=flags&C_FLAG; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (temp2) tempw|=0x8000; + seteaw(tempw); +// setznp16(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw<<=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (tempw&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw>>=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (tempw&0x4000) tempw|=0x8000; + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + +// default: +// printf("Bad D1 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD2: + fetchea(); + temp=geteab(); + c=CL; +// cycles-=c; + if (!c) break; +// if (c>7) printf("Shiftb %i %02X\n",rmdat&0x38,c); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); +// setznp8(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x08: /*ROR b,CL*/ + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x10: /*RCL b,CL*/ +// printf("RCL %i %02X %02X\n",c,CL,temp); + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&0x80; + temp<<=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=1; + c--; + cycles-=4; + } +// printf("Now %02X\n",temp); + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x18: /*RCR b,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&1; + temp>>=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=0x80; + c--; + cycles-=4; + } +// if (temp2) flags|=C_FLAG; +// else flags&=~C_FLAG; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x20: case 0x30: /*SHL b,CL*/ + if ((temp<<(c-1))&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=c; + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,CL*/ + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=c; + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,CL*/ + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + cycles-=4; + } + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + +// default: +// printf("Bad D2 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD3: + fetchea(); + tempw=geteaw(); + c=CL; +// cycles-=c; + if (!c) break; +// if (c>15) printf("Shiftw %i %02X\n",rmdat&0x38,c); + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x08: /*ROR w,CL*/ + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x10: /*RCL w,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw<<1)|templ; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x18: /*RCR w,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + if (c>16) + { + tempw=0; + flags&=~C_FLAG; + } + else + { + if ((tempw<<(c-1))&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=c; + } + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x28: /*SHR w,CL*/ + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=c; + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + +// default: +// printf("Bad D3 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD4: /*AAM*/ + tempws=FETCH(); + AH=AL/tempws; + AL%=tempws; + setznp16(AX); + cycles-=83; + break; + case 0xD5: /*AAD*/ + tempws=FETCH(); + AL=(AH*tempws)+AL; + AH=0; + setznp16(AX); + cycles-=60; + break; + case 0xD6: /*SETALC*/ + AL = (flags & C_FLAG) ? 0xff : 0; + cycles -= 4; + break; + case 0xD7: /*XLAT*/ + addr=BX+AL; + AL=readmemb(ds+addr); + cycles-=11; + break; + case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ + case 0xDC: case 0xDE: case 0xDF: case 0xD8: + fetchea(); + geteab(); + break; + + case 0xE0: /*LOOPNE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && !(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE1: /*LOOPE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && (flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE2: /*LOOP*/ +// printf("LOOP start\n"); + offset=(int8_t)FETCH(); + CX--; + if (CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=5; +// printf("LOOP end!\n"); + break; + case 0xE3: /*JCXZ*/ + offset=(int8_t)FETCH(); + if (!CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + + case 0xE4: /*IN AL*/ + temp=FETCH(); + AL=inb(temp); + cycles-=14; + break; + case 0xE5: /*IN AX*/ + temp=FETCH(); + AL=inb(temp); + AH=inb(temp+1); + cycles-=14; + break; + case 0xE6: /*OUT AL*/ + temp=FETCH(); + outb(temp,AL); + cycles-=14; + break; + case 0xE7: /*OUT AX*/ + temp=FETCH(); + outb(temp,AL); + outb(temp+1,AH); + cycles-=14; + break; + + case 0xE8: /*CALL rel 16*/ + tempw=getword(); + if (ssegs) ss=oldss; +// writememb(ss+((SP-1)&0xFFFF),pc>>8); + writememw(ss,((SP-2)&0xFFFF),cpu_state.pc); + SP-=2; + cpu_state.pc+=tempw; + cycles-=23; + FETCHCLEAR(); + break; + case 0xE9: /*JMP rel 16*/ +// pclog("PC was %04X\n",cpu_state.pc); + tempw = getword(); + cpu_state.pc += tempw; +// pclog("PC now %04X\n",cpu_state.pc); + cycles-=15; + FETCHCLEAR(); + break; + case 0xEA: /*JMP far*/ + addr=getword(); + tempw=getword(); + cpu_state.pc=addr; +// printf("EA\n"); + loadcs(tempw); +// cs=loadcs(CS); +// cs=CS<<4; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEB: /*JMP rel*/ + offset=(int8_t)FETCH(); + cpu_state.pc+=offset; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEC: /*IN AL,DX*/ + AL=inb(DX); + cycles-=12; + break; + case 0xED: /*IN AX,DX*/ + AL=inb(DX); + AH=inb(DX+1); + cycles-=12; + break; + case 0xEE: /*OUT DX,AL*/ + outb(DX,AL); + cycles-=12; + break; + case 0xEF: /*OUT DX,AX*/ + outb(DX,AL); + outb(DX+1,AH); + cycles-=12; + break; + + case 0xF0: /*LOCK*/ + case 0xF1: /*LOCK alias*/ + cycles-=4; + break; + + case 0xF2: /*REPNE*/ + rep(0); + break; + case 0xF3: /*REPE*/ + rep(1); + break; + + case 0xF4: /*HLT*/ +// printf("IN HLT!!!! %04X:%04X %08X %08X %08X\n",oldcs,oldpc,old8,old82,old83); +/* if (!(flags & I_FLAG)) + { + pclog("HLT\n"); + dumpregs(); + exit(-1); + }*/ + inhlt=1; + cpu_state.pc--; + FETCHCLEAR(); + cycles-=2; + break; + case 0xF5: /*CMC*/ + flags^=C_FLAG; + cycles-=2; + break; + + case 0xF6: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*TEST b,#8*/ + temp2=FETCH(); + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?5:11); + break; + case 0x10: /*NOT b*/ + temp=~temp; + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x18: /*NEG b*/ + setsub8(0,temp); + temp=0-temp; + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x20: /*MUL AL,b*/ + setznp8(AL); + AX=AL*temp; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=70; + break; + case 0x28: /*IMUL AL,b*/ + setznp8(AL); + tempws=(int)((int8_t)AL)*(int)((int8_t)temp); + AX=tempws&0xFFFF; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=80; + break; + case 0x30: /*DIV AL,b*/ + tempw=AX; + if (temp) + { + tempw2=tempw%temp; +/* if (!tempw) + { + writememw((ss+SP)-2,flags|0xF000); + writememw((ss+SP)-4,cs>>4); + writememw((ss+SP)-6,pc); + SP-=6; + flags&=~I_FLAG; + pc=readmemw(0); + cs=readmemw(2)<<4; + printf("Div by zero %04X:%04X\n",cs>>4,pc); +// dumpregs(); +// exit(-1); + } + else + {*/ + AH=tempw2; + tempw/=temp; + AL=tempw&0xFF; +// } + } + else + { + printf("DIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); +// printf("F6 30\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); +// cs=loadcs(CS); +// cs=CS<<4; +// printf("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x30); +// dumpregs(); +// exit(-1); + } + cycles-=80; + break; + case 0x38: /*IDIV AL,b*/ + tempws=(int)AX; + if (temp) + { + tempw2=tempws%(int)((int8_t)temp); +/* if (!tempw) + { + writememw((ss+SP)-2,flags|0xF000); + writememw((ss+SP)-4,cs>>4); + writememw((ss+SP)-6,pc); + SP-=6; + flags&=~I_FLAG; + pc=readmemw(0); + cs=readmemw(2)<<4; + printf("Div by zero %04X:%04X\n",cs>>4,pc); + } + else + {*/ + AH=tempw2&0xFF; + tempws/=(int)((int8_t)temp); + AL=tempws&0xFF; +// } + } + else + { + printf("IDIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); +// printf("F6 38\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); +// cs=loadcs(CS); +// cs=CS<<4; +// printf("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x38); + } + cycles-=101; + break; + +// default: +// printf("Bad F6 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xF7: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*TEST w*/ + tempw2=getword(); + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?5:11); + break; + case 0x10: /*NOT w*/ + seteaw(~tempw); + cycles-=((mod==3)?3:24); + break; + case 0x18: /*NEG w*/ + setsub16(0,tempw); + tempw=0-tempw; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x20: /*MUL AX,w*/ + setznp16(AX); + templ=AX*tempw; +// if (output) printf("%04X*%04X=%08X\n",AX,tempw,templ); + AX=templ&0xFFFF; + DX=templ>>16; + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (DX) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=118; + break; + case 0x28: /*IMUL AX,w*/ + setznp16(AX); +// printf("IMUL %i %i ",(int)((int16_t)AX),(int)((int16_t)tempw)); + tempws=(int)((int16_t)AX)*(int)((int16_t)tempw); + if ((tempws>>15) && ((tempws>>15)!=-1)) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); +// printf("%i ",tempws); + AX=tempws&0xFFFF; + tempws=(uint16_t)(tempws>>16); + DX=tempws&0xFFFF; +// printf("%04X %04X\n",AX,DX); +// dumpregs(); +// exit(-1); + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + cycles-=128; + break; + case 0x30: /*DIV AX,w*/ + templ=(DX<<16)|AX; +// printf("DIV %08X/%04X\n",templ,tempw); + if (tempw) + { + tempw2=templ%tempw; + DX=tempw2; + templ/=tempw; + AX=templ&0xFFFF; + } + else + { + printf("DIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); +// printf("F7 30\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=144; + break; + case 0x38: /*IDIV AX,w*/ + tempws=(int)((DX<<16)|AX); +// printf("IDIV %i %i ",tempws,tempw); + if (tempw) + { + tempw2=tempws%(int)((int16_t)tempw); +// printf("%04X ",tempw2); + DX=tempw2; + tempws/=(int)((int16_t)tempw); + AX=tempws&0xFFFF; + } + else + { + printf("IDIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); +// printf("F7 38\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=165; + break; + +// default: +// printf("Bad F7 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xF8: /*CLC*/ + flags&=~C_FLAG; + cycles-=2; + break; + case 0xF9: /*STC*/ +// printf("STC %04X\n",pc); + flags|=C_FLAG; + cycles-=2; + break; + case 0xFA: /*CLI*/ + flags&=~I_FLAG; +// printf("CLI at %04X:%04X\n",cs>>4,pc); + cycles-=3; + break; + case 0xFB: /*STI*/ + flags|=I_FLAG; +// printf("STI at %04X:%04X\n",cs>>4,pc); + cycles-=2; + break; + case 0xFC: /*CLD*/ + flags&=~D_FLAG; + cycles-=2; + break; + case 0xFD: /*STD*/ + flags|=D_FLAG; + cycles-=2; + break; + + case 0xFE: /*INC/DEC b*/ + fetchea(); + temp=geteab(); + flags&=~V_FLAG; + if (rmdat&0x38) + { + setsub8nc(temp,1); + temp2=temp-1; + if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; + } + else + { + setadd8nc(temp,1); + temp2=temp+1; + if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; + } +// setznp8(temp2); + seteab(temp2); + cycles-=((mod==3)?3:23); + break; + + case 0xFF: + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*INC w*/ + tempw=geteaw(); + setadd16nc(tempw,1); +// setznp16(tempw+1); + seteaw(tempw+1); + cycles-=((mod==3)?3:23); + break; + case 0x08: /*DEC w*/ + tempw=geteaw(); +// setsub16(tempw,1); + setsub16nc(tempw,1); +// setznp16(tempw-1); + seteaw(tempw-1); +// if (output) printf("DEC - %04X\n",tempw); + cycles-=((mod==3)?3:23); + break; + case 0x10: /*CALL*/ + tempw=geteaw(); + if (ssegs) ss=oldss; + writememw(ss,(SP-2)&0xFFFF,cpu_state.pc); + SP-=2; + cpu_state.pc=tempw; +// printf("FF 10\n"); + cycles-=((mod==3)?20:29); + FETCHCLEAR(); + break; + case 0x18: /*CALL far*/ + tempw=readmemw(easeg,eaaddr); + tempw2=readmemw(easeg,(eaaddr+2)&0xFFFF); //geteaw2(); + tempw3=CS; + tempw4=cpu_state.pc; + if (ssegs) ss=oldss; + cpu_state.pc=tempw; +// printf("FF 18\n"); + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,((SP-4)&0xFFFF),tempw4); + SP-=4; + cycles-=53; + FETCHCLEAR(); + break; + case 0x20: /*JMP*/ + cpu_state.pc=geteaw(); +// printf("FF 20\n"); + cycles-=((mod==3)?11:18); + FETCHCLEAR(); + break; + case 0x28: /*JMP far*/ + cpu_state.pc=readmemw(easeg,eaaddr); //geteaw(); +// printf("FF 28\n"); + loadcs(readmemw(easeg,(eaaddr+2)&0xFFFF)); //geteaw2(); +// cs=loadcs(CS); +// cs=CS<<4; + cycles-=24; + FETCHCLEAR(); + break; + case 0x30: /*PUSH w*/ + tempw=geteaw(); +// if (output) printf("PUSH %04X %i %02X %04X %04X %02X %02X\n",tempw,rm,rmdat,easeg,eaaddr,ram[0x22340+0x5638],ram[0x22340+0x5639]); + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),tempw); + SP-=2; + cycles-=((mod==3)?15:24); + break; + +// default: +// printf("Bad FF opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + default: + FETCH(); + cycles-=8; + break; + +/* printf("Bad opcode %02X at %04X:%04X from %04X:%04X %08X\n",opcode,cs>>4,pc,old8>>16,old8&0xFFFF,old82); + dumpregs(); + exit(-1);*/ + } + cpu_state.pc&=0xFFFF; + +/* if ((CS & 0xf000) == 0xa000) + { + dumpregs(); + exit(-1); + }*/ +// output = 3; +/* if (CS == 0xf000) + { + dumpregs(); + exit(-1); + } + output = 3;*/ + if (ssegs) + { + ds=oldds; + ss=oldss; + ssegs=0; + } + +// output = 3; + // if (instime) printf("%i %i %i %i\n",cycdiff,cycles,memcycs,fetchclocks); + FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); + if ((cycdiff-cycles)@;F zA;7?}DTR^2zyQiuWnhRZWn^%0fbcb(7#NslGctI1K=>UY3=CR#85tTHAbbrDMuts> zObnd?e(tA4XNp+`rmGU zw)SzDvB7M|=mpK#o7=bI^ok_H?)3pqU-=6?SZxAdNTW#|++4o{v?{grz* zot|nlU3U89AN@;&&P#0A*lResLr0O*jA|NYH!yDFoh&>gYArSEs2 z-*8@T|JG~yXAe9rtc;PHejJ&ycRc*FaQ=a(ADjF8Yu_Y)OSk`B_kCLQy{G@L{k|{y z=l1;{0q>mU_o)7#{rzs>j@QcDMc(iEJol;f`x^hJ+p6!!@BQ8Ue(wIqedX)#l-^!1 z`{Tmf?K1nme~VuC=Y*}iP2Kyq@;lxs%kTQiE5GyewApqw-`VfEyxxAV{Q2*D|D?ffz>y}SPByxaFaua@8Sc3OG;i{|&cpT3K}U;X;-_J6mm z?Mt5ju6ws{_x=CN`0xL0oc#Un&wo#=^Q!Yd_T9e!`u^vM(TBh9`+oP}{{5e0&&}Qc z^Zn)ffA8M+t-JI6^`{^I9vd-N@Vd=fc8&esk7Ey%<^L7@>+ApH_4D5Cd(nG8&x?Nc zZs*_H?(g?%U!PjLeSiA>*z&#KALMSoTlA&R`d;~?Z@2Sz{<~LgU-9{FdCh~f-|zix z+#mAc=Wjm#^!DK`CF!r8 z*qeB+slIe&pZ=^P@<%!LKlJ%i|Muv;{U48i+g~jF{eDH~cR~Jpw(H*B&pfzK*LTwQ z+ta>gXEv2HUb7Cq@!vPga(}|@f9DVL)vImXGk@9F=*-H=kDun3H6P;blaEXPeUMY1 zr~l&X>=^w$CkvbB`{}+HSF(8j)^*46qCfXbgr2`!Bz}*r;(fXL-tRSE)_wnbYX83X zw)Xz7&1=6n@2`8?{(jHX5BYb#A6$C>*V)~#_LqK_o%;V>`2Fd-zsA1bbie#+=*9Q- zFTJPFJldZbVgF9}#@fdp?f*S~l#;*q(apzQZ=Y%(E)3cFFl5og1!<8hqQjz`y7r_- z?_|k5SNNu8*0G}+o?L~Ko=n#GcFE%Fn=2n}?w3Ebh?}Jr$8>sg&JMG^ZcNkV7%!^X zwp~#=##ohk_}TZcRr`u^BDOiVFIv32uPPyvXLj83ExP|tEGiW`zGZIjjBP$oxq?)_ z#GbNV`rk0nR=(N3JNaHyyz_p)7hher`95;lwsFC>Q0a?xlU&|L{te;1H}70)yYuri z&krtt@~QID&fk67*B@OnwV0MO`Oh`zR$gwUvo3tK@Ow2a`Rb!1tD?(1T6&|Tj$c*rWSTT> zTXH0yZ}IVkFTGg~e!h`*=n3b!=9h<;<qt$*;0KzW$EL<=(ua{@I@^KWEpjylyii@nrcKhA*a{5@mL&|Eys= z^E<^ly4JkY?NCb1^~ryiota^B+UWVD1AdwN4d>?j*mujG?u$7-_d;xhY;s9sU0Gwm z*_lD>3fLw;xl&=mKot0s%A+36Rxm@{7aVUY65XvKq(suEEPcZMzF3|kl(?|Dh% z_~d>yF+pKZ<=Lu}oG0mH6y4|EB7OS1kB!rZE$21* z5+)w$R-5P%Jnz(E#q*By-UtfjDP6McO1c%kW=YPZ1h*cpg*SigRdq>lo;dl|wT&i` zS{)9nBeu=Iv|cUfZ`8V}oYT*RDsov*KCF4U`YbE*>*1ijRlyYiq>elbuo>Fb; zA6>|K^U$`|4-3!NOyg83n)^%otjU$xA@Q?+t+t%HYkpDHHajzW-k)m8T7UNFBuO-7 z{qWK){hq-bwCmBrxo-DQy8e?dH-Bt@|^JZ@$+&k`*KZM;by64OAdHS0xzt(3+ z?LXRD-u(Vo`0u)k8@zXH6ZOoWvn5{S|1@vDesf9G6YtQd-yGboN>ThAOp$FSnv)F< zG@M)Lzd6t0^J-V2owhv}qOL| zqX(QV#u$f{Q`|R(I5bX6+Sp*DyEAFtyWoxq z=M)zde|TwExsyR}?qca5o60yIez>L9a(I32b+M~QlGMDqUt2EPX7R_;Q1IuSupUz1Q2YPuti@mKf3rUKI=%Iqz^}Lk?S2>TXkE;fdRB)o!u2-EuqY z<)z%R4-t5#ggP;6RzMayN4=oBqg z#d9^0g6R(3v-uxf-uNemqrWpqY?rS~&9rR)rCSy)_9->Y>iOx%S<9>WB`I~ia7ui1 zu&Gnn%Bi*KniJ=&v~o>d!M5Uu@5voy!wsxZ=nHkyekCYVWs)H@?k@=Mm0X z@%oA5{K%G_TJzrTSsb@M{`1A%@BiMZ|Mm91+`kpiJ}fmW6J_4<>PDz~%=Mj1J%rT7 zFSUHzlVcRKXTy?*rrHlLW*m7Vzc_BbnA)R>9(P+xGPJ{jt|zWM9We7jv5nk8#inl( ze3#P|1-p-DE6tD*?2r7U(&~LA;Z&>5sx2lR49{PO>P)y2yXLZ!P-$XfU&nOSw=!a4 z&s|TQn|NfcFyr-%-BP*XicWe{PphPMYX~s5>jZk9`t7o2&yHVFZ)7LjVt5ep<%vo2 zzADdhy*1Me)V576O7I8}n|)RG^feZf-9DV1oc*0=3O#1s&MNeLt9VyhZte2vk&6q&bX--~sB?oIZ5J>dy&po-I3;gGdLTjnY!r7Go4 z5SgpowC4J$6#|0KI)7xb%+FToP4)HOyKLY3u&b}7Jnyot)lO|X^`*A4W52_19!@EC zm8+4TtQ7sLl(^asteX@u?c&6leYszqzSM0zrL80;sU`N!CGz9ey8N>l$2S{DY%p4p z!x@v-6vA?1^4#ljZUr_!O&d8LvTmwy^mu)zgtLglDXMADo^OY3au?fu|Dxogz24dN z&ZcYYYyUL_Pb1a{tw*39o;V7t$Ug_8>Gq?c_`N&7CX%zS!V z`Ky`RY&S<($Ib3cnG#(&*Kh5^G->0XIkq=h?Tm#MUazUK+otW~ZK$Ufq82cpGtB!& zg4?B2zmzhwxIdl~S{vo^D^=*c&xe;x%Brn9z9_L+{=WG|?tnmw+ZyBBZz|Sz@>z3U zo3%51=IX*@%^&uP|5km!{76pfnL`$;%g-b~FI;xq=y}e$las#J%v+fnI>~U~uTFOR zk5Bq5yx#xXxLV=>@AW$Y>Y4u%+rBdj{yM0=zCn6JNlGT?#5pUM`UJZPEkCw>?q0uA z4WC&%=TA9eYPEiKX_C5f(#8CzTidQyeVn7Y#_ZQxd8w0YuGi@)e_AQGx+Kh9_;bjs zUyuAuTFzY0G&Vf1!<5bX%zEanvJv2UKxj<1t)_dnm{tXpWL zRPtu}?Rx@WrpzceVom0mpy*!c(lV;b@aUz6ycYc+9iI%XI|!nQ##BuoQ`Qa zN~_&iMyhBCVsOxP89wS^4gjmgbz73)bwm3Z6Sf{EPx$ zHQU59UI{NAEXdg%dGgPsqbE6DB$eOf-*v|8n(UFy%#3@dSibp_qgDI1N8%}`gDv0I zdzvc^?`{vA8PqGcWuuXE%uGd*n{~^MZ%+SaYCG*yq|bKa?w_`Q^FG_#efaqQZIQ{t za~oGPHNM;VeBNJ=HSa6(?AGY6N%+5zIb#Z!#h!A$tzHcV3Cw{CN79-Cd$P4Bn@m$& zFn2<*o7&8@JBh!x&aye@TAuRj7|Wp#Cl)2HoqPMujrnOlVcUA^*3Zq>H$P)JQ(^JV z+Gs1jj9usD>t+-L|LN;O@tzPEp$`bCargf~S2@`8(T%{R_j*yWZ(~hj#st z`C@E*++bB(W8KRyGumF{9}3R{Zo&FGeL=GZuz~PP6_`% z8t7ah90Z-FLlA|EJ#7Gwdfe@q9V{YWI~>`)+m~yTbOY z!dlOI?$k?Z`BJtXE(?@i->hEd)W&=8HS>~L8x1}RC;J<%-2Yi>N><|EX`0ct$lul=s;GWkdJ&INlW>4z8onU#Gp_p2xGhQiCf;g3HYwEbYodF((aw{hEw zm3*B%YO@lzJ>0MF%5XF6*Wz%cYvD@w{@c6!-79f$f6Ia884suK|L@rUvFMDWjjUV7 z>+?b>8!t;Pe79xa5|2&q(;n<;3Hbb7P*=Ee{)_WMviA<`@BV6M$zyeKUC`FKRkF)Z zJ$^80)>M9HksGqB&u306e6vU3_rxH}|7E+v?}qPTv~L6zuF?5>w?4G~cm31PPl@{B zM@r4_^!P2;=l{~>ti9vsvezmO$HkJ*`#IffWJ=h}^l_HMtZw`B_x7Giw{D+!#JWRo zZe8AzB@<_{y*ia&_J&>Pvc2uPpN+S)ZYt)c^URj{Ic-(;^H}vgOQ)tC-xTbweJ)MD z&EUt6E*;fv{heO(C#Z<33MeHvJx)RR}Tu5PMfm&Vg4-DV=GE0typ2}`n@Z_ zwg2k-wO1srgdCg8$<(8(q*T3Vzxt%U%uXT22Z1(@`f`GbZW4UQU6u%+^iD{Us3c3X$$E0?8uhfcllp+iCk}MTh8K1+e2EE zjV-3$^7*cNt%pnNbzyO>=p4DfecSK#Ob&k+uGQivGbwtR0%P^WdD>IF%rDn%kNc+h zzojqsDeI1p$E0Ovo!S3x_dmI9xAb*%CokzZ+BE;tk|#SFob1$v^QElqr2Xwo+4kM3 zmJ_cx-(90$QS)I5T$@=fB;On>f%e3#;5#t}9%;z7SzWB5={n~x<$2JPP7yP-UUGQkvVvCP$ z+J#qn-3y=cx)(g*Z7=w->+p^Gw{>r<_sLiHzdd|u;@=t8JDP6&tDNE?)!v=DqgQE7 zk(|bqi7bptO8*w-dhR=B7W@2Lhrp2*0hYPWxtW4>o!j_5>Z<+rP_l*mW}l`=m* zBx)Dj{l2rWe8S%+r>nnt{qyyjFn#Ice|xI~)=rrs@=LDe%;QJj?K>LZOxDN4b{o|6j+(G-=mxeZ<`tKhTzF#A?e4bTruXvbY z#Op(^`XAgB)MAzYT&&u3pxC0Kf`6Sw8N+eExK8c$)_tqj?dJ-QtLJfFZ|}uY&H8P= zMMv#%zT}q=1a;&r8h)MPI>pU>;;Pn%Zq*$-9VT_mSZO5FKSQyX!&P9-dtoPu2~yYI zmR!s&ewHjfcdgm4=-853w==fR%E&i;xmj)3kr=DlzF%H`jw|lICM}VhpK#~ip(UGp zJ=ZsPyleM8&hcl@4kOD0-CrvdZ)7x88Mas5bG*1cP+>;=qSA>1juRE_^-Yqw=k-q5 z%*(2)x}=UL({G8zo_f!x{Tfa87k-G`Q-1v4TmQOGlc(o07=y}9^?4OadmsKX-`B42 zB(SaLGq*R>e~x6KFU1>nZ0Ojz^OEbnbkk)=*16<6?eG3-ox0Xz~8s^A3ss{}=e@ zsrbH5`@g5xKl1wzPw>OO)%;06Z`7TUzuA1NQT58S=>c=r zD~GRD&=6*9Z|V9Ia8x-%w28Y$rBH=?vHH0jAE9e|J=yz@f2nf1-}_~jz4ABL^__kh zilWSubIx9Es<2*qui&A8lhw9ev-{5e+WPOzrSci~KIbn=aarNEG&sM!Eo0KFK#l2v z>#inT{`qO=HE+df+Llk&7_OAu_$2d6u^E#%N9553lCLZ^cdYA(TD@aJ!wg3C{Ebov ze7deqP-g$;B^3EAcS`5NXUzA-ZWsPDHf;EoZ8uSW;l|Yx4832TN$3Adoh6}ev1py) zeuXY|@lOx3tUnj?>gZo{6|Yr2F>jUo+LG%tN)Lw2ICvy&QHP5DeD2~6fmsr+FZ?-* zCfn6Cs=eI&TGytwjJe;wR_=bq7uTAf^XDBC-}gh}-=E_C2mb#)W&hZ0|I_H-Bmez9 z`~R+9|4=%c6Uq2XS>^%d19b27Y=@#_U zOUANNg1t}JP(IeN^t_T+cku~9mU8boF;kT1-V8l+u88HUM*+9;0+-nRH+XK8EnvQj>`7M_yHlcS`lyLi8Fq4k!v%6Z#7t~p(($$#S_AwQijS(-um^Nqd>s*7?b zf4Q&pa^JR%oma1x&ao>N)1PD2`g~qB<9XZPHh%N%n%~z=e|NO_&o7a4^R4@@l?f;B zS|2_8_K#oY@`q=Ber-{l=X`17`dz=GD#L2x<|OV6(LcC7`0d@sE6xFSwW-I9*`D#b!cYE6pADD03uR2+y*%O<}@}%&5 z?DxNV6aTays_9(v@G1w#qGNBKbmqwH|71}2>eyo?UY*xZdmA2UZ7QkKslC=86cdsE z_|Gk~bCdn{ZoBE$JV{?E?N7R!iO8%{k zlh>UJnSNu}D_-fPO0Fh0t;s7_PR}@P+ca$&`I`$18ann#e?OLV zR$f?HSo>d!QdpJQhK(uaFHfoU$Df<7Y9P4ob%avm&y-It4M&{@+Ys^%W$)d+E=y}aLp{XsY=~;5`*hiVuE#~Tr+E>3$-F`D-$;W^!Rz7xRr3V`$ z-b?=4^v_!C^@s*4s@ zF#X``e8s4GQF5Zsq93Y)U7cmwUWu1n6dP8yA30U?f8#v!Q%6^QH?-b-XUPX=|MS;x z-l*kx@b33NXDMI1dHPc}?)k6qEc}~5V$}>DVHq{q_wjpwTCx1Qva0@Lg6GLgn{P@! zuKzLD{?MIIqBl0z>mT!+-Lb;kTZPr)_uqv(PR}@TwBvk$g|Ew`9VRDt*2(#oPORxW zHB0ox%B2e?KAFV%B2x0nnWWnpi}>0ew`5G$OHV4!G*EI|?Y?0~=g!NrD$a*)&I$2h z$+>80x%lLfUbTrwUFJ`U)4ODUb>gQ!y%z@~rmJr9NIa3P$P_()e#?C|DMgi;QVKn; zT`f}O%T|8Mb}G|(n;rg5pgCoU+C!cjr+U_WGbwKfZQmneQ5d*3B=7_)*V%$x*IU=k zvr)L+|>Ri>{@$H43%3?dVFE&+29*8|(HLF25QQ(w?<;3E7 zK1remN1iUc6Y%Uf=kF_Np{*3$Zt;X_y`TAc=_O=|) z+sydjm~`HbX=(TLi#GW#j8W|j625tKSN=wUM+g3;R!zA7ddtnU2M;!?&sYDt(9b7@ ze_qY2LYq&$>mS`&DZa7rpGZ`+w8Xb4lb38R_Q@7&q>Ya(^E`6YRYGFp?mUmlxejL* znRi`y=YQc{-^CnW&)ydg{@i#LVEbwbvEL744V70o&D%3A%X!y_c8Bx3Y(jBPpKYv+i`(^fzeNq%`Z#Y zk1(*!nxHJR^O3>AmVgXn_wz-S``mc)m4xQ>w*8r-Yj|hri%Z2)eAP!>CBJT9*LT}~ zS;+0!(Ey9;qU`MGt{v}g?{?u?k;Bw9(U8G=W!tppe?O|*|2$x9-;`N%vM2U9LtfQk z-|$O^e}%476D~+y5EZ+VsdM3TkL5NVJPIH7w?A_dns}vdj@A99+4`M*Rj-bwZ!9Zo zRxt5hq!+3i9So+v+evCti7O zzR8wu?DxV^&Sr~z>bJkb6WK~^tHq=rG4*)7>gQmc!d2P3O~>Z{nawY@Y}>eZr)$p= z_1~NxpH^RrZ(QPa6MP>27{j z|E5{)-nNa8Hr>lu?jrJNLh@m;>sP|t=7!7cI#;8ovQkn-W72}el~?x}R{_pK_< zHgKrE;JEz0YNxTn3cnA=meB$C;6jQ3ldA(rElwSus974*Ym$IbK zlQmnktVheKs_vA4ObctLP>-5&>RQh!&kqzV@OUYqCQ+Rhq;b1DTk!b~o3ftRc80oF z&&>7I3QJ~tD_vR69=F!iqyGtew(!Oli;@KXgUP{Jub#GbRpkpmNl{Ab+_~-EkX-p2NSttYFWf2VitVeniQ*5rr~HMbS3Y^^Taot`{{ zv*Xme9wi&^=u1zG=eBM){(Vkh(LSNtxM$A7Jxe9#t`b%VtcX#Z+1!>|GCrhXp8Z$@aG54U*_Fw|NjW{{2$j=n})~pCtp`&nDu3^ zim$uOi9=$!akDcj%@{O))jYj?ZGpcL$Ib0$SVGrdTT<0OQ&?tupX@=GQ`HA#%PKxq zDNT)C>wTMPyKL?U;}l!nDGQZZ7h3&0Qqs3^TS)i59Bq%YS34qaX?L!QsxkcQ@wR5= z%=2k|62g3YHtswx{`P2>szBFk;bnZDpA8n8zC2}S=;HqK-O`I~Q`18B&+@YaTH48Ht_W9Rac+{YP4f7b@>IlAH03%4u$cP(0a7hL|UcG-&k z=3W=ELuc0=iP2NPzI-0wfXCM z+79zut(*J3$>vpWrBX-8pWJm%A3tbJ73sF~VUz2Z?X;?LD%5Xq`M!Df625sAzbr3a zKkHFCZRXOYlDps6T#Ucl!?~gEr0}^X(h`ddJ2jOS2W4EJGHb`9j#-I18yB#cIx^o{ zzvK8Hlhj3DvyWa`S@E*M#_O(^qMuaVeZDyh&3)MOk}6&P_&s%CUToueoK!Z@oE|FiZCUfxICdR9` z+}=H4T4S`Zzp5d|w0~#qXNfJpkL;0|c;!LY(QuLW*?#*)=VkO9Hw}t$w%+)h$vUnu zX#S6wO?Di)r^}VpH?5h~er`c$l5YQsH%h6oyCxjYSj(-hn3RxRG3nJ4@!v`;32)Ct zA210j_!Z@T^Ps`TOl`f%OJ^)KI^|bV$iMkSalxkNf-LibHr|LxSnc5&R=3S;cFThq zinmTY|7=lGus-7N&x`LABhLHY7GaiHaOCQOoAoblNtEpF@X*x|On%Ah{$d?}=fRMU zi2_0oW_8c0z9{ceen!S?_EuFhJ$zJ25C5QeG% z+gYB6UCa+Z;IPg;arVz;dygMY#?BjbCf=~hz4!USik&m8pI>Mxb@IOzxACjh5>s=Q zlfuRvFU=LbO`^AME9&0TKZiAc>7kFSW=$|rwdhm%%X_hX@AdZ0_uFeV`hPGSygq4q z>r1yc_rtF`e0DXD|5R0&dFjnl_tm-UjW&F?G#BrCQR4Y~>rt?Z@SM$xW4R|L@}28<;hwHpQ*6tC!lT(Q^3Vu|lQi!85dP+}$i4_aLH7C~BHHQ`K$R zC*Q6fJ!ZJ?f|^o6=a*XJYvW(b7P;a^PHMr z_t)Q>-}qANjDPIv863JPtj?Eo4xKyX7nkJew?DA=N1fs0ZzYi>X*@xdGyfIJIBYjp zWLv?r^mw0aVD*Bx)1ON}l1;enIlWlxRO&~q9safK594bXZ~NCv*T35Ov9+!xzs9^@ z{M_Z@PhB^5hqO4`^ewHgzu~er=-{bOlPYw4CI_Zyv^{e*`M12??(fX=|GAexdtLO# zitWRT#r1@VDk2zW|%7sitSuyStm4cDk|ZD_^RyuSUm9T@fiuV zKEl>&5%NODQaRfuZd3c9q}$1D*OsR|#^UQORtsE1p$`7YQ*`N1OXbt#%hPtxH9R|2=-c~9F*XIQ#Rf*PGaP%wK3;1$+; z#pT%|>3;j4Yf^eUw``hvv0riT{(u(mBhM}!*>c=aaDS_e?#qHTD%)1NIR8I&n%7Az z*GWZAZLgu)*?lQuPOnevlpgzXK3+x5X+_eBi{5wsP8YBjHdSB$;Z4f1&D*vzmOm1> z^`Wu2wkK@+%c$axTjuX?SRj45a@D$a!C3#C znC1Yt-E*CfUy?4!@#S59s&qxxkL9}}mahp;E?@Y2l19noGk@A9FZ@xIn}`1O z-~8h@cUE)u#ilbqNW6Wm?UJ&h8N*`jPb`mH#P{&5y31J_+&J^tj-zdA+n8s3ib;Bs zlxeQyaqFeF=5zKV+Bz6uBsqo6**{|LNJI~*AJe^y3{<XZ!+Y`CH{L_YGdWI}XN+q$$-2#EHl9DzuhB);UrcerBeWCdlpE$vK6l@g(Mrsz>4@IT^KZC{JEPju!yj&cQFCnDv?8q?n%s4srRFMs zuazhXJn~ELs!m^_P@Iq@$`G79Yw4=FOLrA`9qS2x@mO`%K_6|Ck9Id?HP(fg9TGA$ z4vvVwKj{{mVeI>ltNT3{h^2=W35VycK9_lQZlZkUq$hEUKKLX>Z8~}LNI_(*=Vcvd z14T9CSxZ{p?V5CKZ~pr(t99ELH3BBTGJE#2n7{T_@c-ldwvO@c$>Bx~()S7u`!4bR zmm|T#(aAW)^MALRmT_)g9^YwiZmo)ABB$p}jL6cOT(ack6?vZ&BQ+JpdA6mD>F47w zOb%iF*iy+J*Q$0?L(yWM$I>}d4##k&`CBnN%C9N&d7&WO^eac*;w*%-`7%(I_jugRGxH&Q!syzX~X;ts&kf9ADw#NmF2JV{Dk`YmVY;OEz0696FW(qt9GsRLLB?Mdvi`-+^ghfoisgug4(qqgLMuj=df&yxG9&+3>_*nc2t>9WPI zbwadKFMXcId1-%*Ov9z?J2l*z7+=1ecA}SaUiCklb8~hl9J&!AQ{PweVXD@fN&OuG z49ZM?F&}057q6Y?b4$>$(L*?(bYbJUCGH<4+bL@rTitgyn)z(K_M>pKww=w~9;e^z z@R(Ta)N{SMWV0ljyN9zGi`bDx@q3d5=T@9(tSwk&+4Pm=>+vHdQ4^ z=LZ+j;LC0R%dec@PdTV)XZ-^GxnPj$tk0<_I-Xa_Q zuKMoA87z^U6%W5i#aUGQ?LJihf znh2A0^%fDgmjZ>8zuESc&rpeY}XXsPrp381vAC#Q9>KTtJX z5Vx9t=0&~Gi?ueJ4yj~XT~0B*S;$|$BXY}fhds=ZM;2R6lR06uO>}Pifo*(Ai}szn zRZ_y+TKxQahv9Mw|6>+KKNJLO10@``I%UZnEZ?@7r=8iedDCErSrq$Uco&lE{nFj*kSULeYyEkt#!Va)_b$aO)5E~dwr={{U*y6^M`DU zou7ymMZ7NyxEJhx{jG4($G}wrQad)N_BvQxy7+WLvhSa58*8M+CB9U@U4Q=3FWtKe zEH8T)3#1q`JU{WRwg^1NzbQMksQwir!?Irgg+j9>SU>RZTy3P>Q2ac6sg}TPWzc&JR=e@{j8EyOu4=f4HM+W~HmplIV#@ZSu*l0`dbah3{K#3y zQ+k}+ZC6z_XZA}R`2S;;&n@qgH(qQXu9^Q0$u;VEw}A6W)lM0$t8HD(6N)Y=^2y&~ zKezt*$4N&-XNs(RGHtuHvuKQ)N>N^^@cr6%N9W%D{J(ON4Xd~z`=cW*EVq`l8?EtQ zHfesjlHp&=Nm;E7jECuwdLlH^YW{bg5Dg|uF`mVN@7x!f*yIVSfqT3DKIRA%|CT4qcYd())24>35M*Km^hy5yIn>f?5~x*x{&ciz<0_QsxMxc6_`c9y>n zKOCO-{I{H9gIBHJQN|;4>|P1g*f?BDy|uV5J!19J)Ah?=yztn2rE9~kdq;xL@3Xkd zwoom1!*VZ|J86p<=OoD$&foGba7|DAE|+OrPIswI+W7pcjZcx-FH!#Ht9+CEScK)Y z4>}ytu(*&uMc%7zj=xW;ixxvi!rCJzGG=}G%o|hjZOaPtZxc%Xam%7BdZGy|@t@8heWVd|?qEXFvh#lPt=s>pOw;o?t?fNyefZNoT|Z@BU0vkzwf82UFpJRkg>yt- z@(5r4D(O=Ywrbt_+9olaDtp`6_xHSi zjXP7olA}}9^13-Tyq@rdU*_V?+DnHg^IqDlJhj3^X>Z9PR?W)yTQ(otS2^*<-K)Ge z?s7cNTXHAISnNCJ$M#pIpFOn1+Vl=qu6y`=!m5jJ4vX7=o53+t#d77|oke}#e;3?- zb3oQ*#kEs!)DKteRd(AqL;GvXnVBBUFG@q7%B&0Bak1^Ll#=<(UAtv&?0PgIi6Lg8 z##L7LG~0S>p3F$Ty^3pY<~W@Bck$T%m)Xr}LMsXq*KJM^IM5;xyf$hw)0)F^{BO^O ze&JYF%=-AE#lb_5l%`EvwJ7Upv(2+-U6&T5-0*jqG+QkGRG;D3oE6K|H?w(%7A)C$ zx5?M1OHzu)U0S}PZL6Cl>{c?wmZ_h; zexbK|g-oQA%LIFi5amT7*Zx*0K3G;I5$jo1x4JzecZJQHwB3+OpX@JpK7) zls@SRp1LMcwn!yCbEe9Vm!T}eNs;@sg|g3VWN0zUX*zPaI67(agTI9n1$gu{d9uHqlgG%>CU}a`-gwD3{=K5{$qcc-Vs`$0bjBc~ zh$|ss|2B3HNB!9E4ou5EMOTGtpOQ0{>uOwo|E=fYAiX!YXJjXw|Fmb0!FA7w8QR|B zi!!mYK=Q*{1`S|4}-3lh~Fh+!Psf9|6DIp%_(Ou`IUT9eS@w0SNn#wm%r-r_Al2-*ml$+ji+pL zvf0*h_s_w}xzAsFO?5v|@@(Qf?PnG%*L5D~bSPY8%l*n+@cQq?*>gRz3q(B+>=mB5 zwO~E7@FayYj_g~!mB%Ynt|!DlVVV;+eSz%lx|iYld!w9!VjmrQQFGt7-s#vnR|fMr zHHWQVHp(V<7c7hr68B%U_!8fn`|VjzMGx)jojR*yt+P=3>I)uT2A&J^ZNG`QO`I0D zO>KdteB3?7h4Yxz<#{bTRN@t0td;KR$za;Q!*^0mi=k&)xn+CUrQ>0F9+PMNc>c=6 zlETfsKJVo*oEMZ!4t?dUxwLZo`P>8VC+w5C>2)@6SnS2{5Ji)47f#agfb{wB(vr2-SnL|g{jiaDdio)x|7HUtf-pyLH zb6>0C^SFY`qDdl8i(I|-6n|OtUWjSN`VPj@Gajb{RgZ~Y4tja)SVi_(yA&VhncF)v zKUJOov`B^Z=B{Z;Su;Hxqy?`}{@zoUzfO|fEyj3Za(uhtH0n$l4pP4WM>{d+EqPk)xR%u91M~-KKFd}tb4;J&Rr^hKi5gty74^bQ)7Jj za;eOrEA5*N8+?T?7oU#UT_BgZ*X>M`#H8e|vSn8L6asTs3+u@XBz`>Qy~zDRRr;cKX7~ zo7-fpbagKUO}%X|6&LXK=oZF6iHS?AP2DEH@maR7HdesYGi{H+^+mO8#SoR%PHtCm}Zh=VH7Y?o%{DReYJmcop-LC@#5x!w4190 zmZz{tty~rx9rwzMBm272OYcLLx%?jA%U%>qI|~SV6bG4}Sj1`lqQtO%Lt|Ne%e`x6 zT{AA*zR*dXv@N7X(cddA(v??y*I6lzFF+gV(&6t?)tTtpEJ%p7c|{1vAtU3($D2qvNz7HT6+Ep zqfhUaIXkVNZGPWBbK=92#qQF~iB?-T&aQo@5Oj{wL&x(`m+Bm=iDIvWvKulv^Y57+ zkC>t3?9H_AkgQJ$l2!s>sXlDi{Wcg&N! zcD`7{U^U~?qNyD5o=2B1t<=#o(KAZ(tYl3eX0YnKXU-Owr5=ByU= z(3f2#)aLO!*~evp@aGRTvv#O#l#g{b@R_2k=pMBD%%iy~51IDzWi-uurKvaT)e{NM zv#LvWN*r3rKBK}!v$OH(T!z1&bv-{kY?_|fC~;oJY5s!!{=ZAx4S$`_RXTpw-s8V~ z!JK;gR&@dUw(zsv;tKZhhs7Q;Z{uYtsgn^n(&nmuwQ>ElnSZQH)4iwjoPNYy7V%Tj zz_NRViHAbB*p=Cl*Fxqt+~Z&7lK!QBshmTO_{4WVl20`oz421w{^`W%zTQINOs}rl zX>VRbGdJN-4^#j1cea&QZ@$?%QA*TxwaO#O4HuQZb`E{*NO7whLE^PDdit&wCeIXs%^+zPDmkP|?qASPfS0E{ThR-8s{p2OO7M43+ zCoAf8vMo6p$q}+eTAU}bJkfaKh2%`(1wn2<)VJ!K2{bjp5V-~yIIqG)uvw)zn z_b%Z?As>;>rHj9t@C2$|axr>mbi;1z+w@6yQqH8ZZP%$OQ!ABl`)>Y^;p_*YySncCk=ZNHTP`_VORGmd|4j$@kjO1fUTOr$}FFA zrrJ8$ivQbp_np_RZ>K)lNL}5;$5Lce&Hlx-D(oY_-M<5Wm&fg$S(Vuz8!6DjE_im? zCG${OhT9R%QFq5bxbb5_Q+3K=O1J# zZk2J=HZy+eYlEK9pnyKd4Of?LubpJ3m-uea+tj0W6%XH8Wz|J-#KuPzhKH>x_$Fo; z$z{0Zc#Bxa#R*d$du@}Ec|3W^=a?j|WbU_D`P9xDzF{<3a!bGM3Bt(B8K?P?YL!rArVQ7t7UQ&-2S-WL?q9!Jhx``P}qj6t`^mafA^5vQuU zJsnh|SI+8|N{Y^GW3Z6DvBhKinZj}w#hF=0tu}UCUbnR|aLrG)b%zyp%X@^Mv~k(| zjsNiXGwCru|FYk@>3`zJRx^g{h1+g~rYxAZI>)>BZ|Uy6D45RUwT(4cX0p2- z&zE$mO`ERTgo!2fm1O%zblo@+>fQ0%rRKSHL0W0T&1;jtJ>2-z^Nm&dB8y{I^X7Ip zUo=>h%sMGLKp|7k)Ot}(pTI$NH$kC?yPUcAnmTc2-~RAIrF-Xu8Mi0QaB>uCQb{r> zT(Xdj{fbY<|D#9Qu3h4j@(vaGqjXK)y8n*F13M+5PdNp(4_0e9aR=YpoW_%49h-Zs z)8g;B1y?}Up`md?suGX$+ma)89SR8M4SxFerK*_37&P}O|+KnON-jiGjreC z^mn&+?U-Zgbj~3C?`9Wi#o)#FU(_zMa!L|$pAK63d)|j zZcS4?@@4N_QJ%o{J74+uyf~PatZ@C3df~nITN-}~^!~Dm@O@F<-m{_8Be!HnC40!X z1xJ_)E^yTz;VB2yi{kPYq;5ap+4IP3 z@#h&L9!hVOS9ovOzj>?U2RoNXmO-CZJ^68j#q6oqqL5NgrF$)(_2)VN`@l5ot>T=o zaxuF^3zz)*xKV3S%Btpn1xn?I%7b2Nu3(yyZp3JqthS-x;`89W^NhdG_#o+PI9a52 zUT@!-h~NzI6>GJ*j9)xg(%QK0`NIC?(S55AsjPY=aGPyH(bLBhZK9ptf3exI{D8$} z-%D4nm>axuSJ7g>Uf!`(LUW7m;lOPTA#>x?uFoh8`>;s#kJ=PSSIRDt>%}vTJY%T+Ld3z4;wJBhTmS>CvrVyTG6jRTKhiViTubR zk+ijQ#@#3fmL0Ax-WzIMS~gi8`w%jFL4{V2bLoM?la(sYhHRIJ@I( z|5z9v_OMYt-OYWezHuU>bYAz-q-(PcgJahSev@DNHv9fTF~bP;m0es%+Wwa1Gan9A zx!XAHh69f-!=@gk)S9m{@Bjbm=ePUtHave>+^yv6Mh%nI{WmTDx4mh?mdqpu)s7rOWIr zjs2b5ICBjW)q{^s%J@Dv_?+-OjVk%+9+NBGhKI4|&pgyfaO~Um^kpF}W zr=2EBG__8e?fyI`IEOiJQpd)iIoT_xF7^LB_raZ-WM+@_qjnQ+I+Gs7ezcaqiSH3vomg)2rk7RY0$|f9{Cc;&pecOF+d8lG6W%7N$W1TFUS7q$7kStU-- zntLH?d5f9crSLNhE}L$0n$5ml@#SRtCV`~5$vm!kD|HN_y#o1#EB)KB!bv6s={ncAiEZ%bPq??TV z`K@1`7X^K`pP{Y%bYJW2+#^d~N5^;<%vn%9E2Qm6`T_3s4?MRn$lKgoG;>>j@Rs<9 z=DU5NwhqE6lYP3&G*-^fU|xFb*prXaNmCirl6x+f`v)zs{MU51Vh-Ed+W&KoaVM9s z8r8<1ur@xnYE#x7#+@>38W)86mv0qLe#bbY$T(15-7m)V)ghOVMXE|seAm<5tR?zd z7*p6B*1l6#{JO&T{Hodp31!dvm927|w=znrmwe+fSbw{DW#+>dnG4^uFIJ4G|JK7@>fkRi8&X4NvmCmZ( ztsL0mQe@(J>&LUj_ZitGJ_?jx^bCmLxhTmK!un9guys-M&*sxN_FYh6+G6~8as_{f zfcaZJDU*{C=I`QPESR9R_0lC?m*Uj<6PUzVbrs`z3_Xu2wH|-dB(u7zO2#!Jc1_an zE0MccoH+GP=ACwL@7U+kaYUPCiQJltA7wN9v;uQ}GE6pb{a4VdRxLhtspXb)YZjkK zdBJ<&_IF&sAuo#WZeQwQ(8G^nkCzPv%LKIn4k3)$_j{-|TCFb&)L#(z+)7 zH(1={nQ%@;jBSFtX~+A&2_`~cdwJWsc5c}B{_&5G+DmV8&;NZWhS{=jvx4n@a~bc% zfU7GsW@?oRrJb24>CRr^)@3Nn^xzi%-Ma8u$KFK7F_hRcJYFR7?8q6zZU0^!Ja6-* z_j=L0IIm=LV}{u!595n%((47Ds1_Xg>||*7(I#C~!QW-khIxCHXC9fd?3w3=yYI3z zBo<$ne~{g8v+z&$ts`^UO!n^Z%0KA-#&yzR`TXxL;_~ahE?KhGNA0rgj3rZI3sTLz z-ktx(;kZQW!U{dBH=ors>^)tIb{|>7_IRGjsRJ5QvkvW9-Xh`ez@eaYPjK?DgHxN1 zn|y5E(2%gR{tGEX_HaPl%%Ys&x2lF>OUCD za$d;R)T|-IFwX2pY%%X@2H~C4&oC^hHrg@kGsn{;&(*rOlo`3z+!g(NG&j4n>)d$p zz3qhn^Njh*Y#X-BC{>wcotQ0fV4LLe->?1aUL9QjFC*>aJNez$xEb`GrmIG0ojMj| zBxPmLVsE@~$+9OU&%Pb(DV5IpBsG27`Kd`;4tgDBwz$MR;dF5EMlZV~9sjrF@^tQq z$m*&-b#a|@63g9dW?a>;ByK4GV7awhy9g<0^jrdaM(nN;l^ym||?vv)7YnI;z`?c0Qxi~kJYkyqr)xes{cO^^-p?oyTe!?6n?rToUi=im)JUa`Ddq+*ahNEd@t2j ze_Ir$@7*jAYT)$HrZr%BrqX2H$iQZOF~Li(NZ>ti6y5O$u8J^ zZ<2~)#v}8$`)_dFli}M?ax^YyU4Ft5Mw?jguG)gt?~Yu#_E<%1ddY*SN=HI?{=ysISD_kVLf|}!OU>+lI1-)OZX427fTd0 zlANEFxaV5?-lK6Hc6&OP{$_I6`n_!@znTQsqo|U*bNj8&iZTC8=JDhWl$^fn?6jpz zwy!*}`tHx0w%;XPIfKnYC6)!&T@r5)ZoHxKVn<|xU^UZ@qqjO&_peOQs)}D97Wkx& z;mdBn@`j?73O+qE%|G&3t>^gv^!tB-+jGtC{rk4vbMH~7olTe1&wEH3$gTAg?~P(* z|F+iS#l{`Zxv4Utc@BjK|NU*AU-`m&{l_bNQ;w}mW4Ipwz3p}9ih4aBryq5UPrZ88 zoOSZ%A3f@-qjPP_Lx1h6uxkb-Tsb?6b=*a6ZOigH$+N(`hjrcOLt9_p;Jxl9-x|fK zye=j7!$cmX8^S4(X+~RFo&5!_WF(#ceInkGqeZQ#WE-z}=-k3bF0E3ZkDOaCvP32# z{X*cYgBp&rXK?R6`lEJcpLqWFiF4j^lx=(~&@8?!KwIoWr(40TFOm9_x?J@HnYIh? zSBdSBQ`xSN$+yIz^Hg=aLuR_#m-DCot;#N)J2&-U`r*c%3GBNs`dpl)`hjDP(#9KEtBNOwKJcn9;(fdHUsF<=OwgI7ht}`=b?VI4i1i_XkF@-^*c!i8 za;*N>cfS4S_iJhF^MC≤FbC#maZjhew+${vCbp=@HW%xW9d8)m#aN^`guMqK!v5 zG9(!O_pYt4d9j(l{$uF8Rny6L&=;XAWeTcxIPszn*B zTy!jKPw?tQ<|!fb8@q!4zuGS6TrcqYOYBzN@&~!QopofR9E&eaep|KL_ldInvT1hw zou=t4w+99O%h9`fS4#1ggvUC2_r*8W{x@`LNGWYpnz_I%H(K??z55DN50ov9y_wQ@ zt=qN4W4eErL+N=Nt0M_>Qk{5bcnDrxVLXY)X)T}d;*CojGP2x-ZmPXKtTUB=!J21k z8{CgFs(8-2EA8gZ#p#>;^=S2hecumy%sBAof(`4u?ALSHWpAG^W6F+NbXbD1^@C*3 zj#Gb+?TuctB5RS#&Mp6@WY~INXjEVboBcvY`>B!F(K&DCd+&T&yzoGM=BZOY3L8IO zU0)j;(k8dC!9uc|y<@v&*%OXcs!qOl_lbzx))dT7ib(o1*RcANsrt2WxqojC&#%{g z_IjyBnK|>0XRr49&AK<~^wS5dl~c4zf6iHaQtJrAw|9{u|F?1OpPHD+ey~WUdjI|N zLP7gJz7Wp%>X!BB5FRq84cV{Gz7uZuP`E zn?~8H6PGVlZPd)&A0%6IIQ!eo{tnA0{9zaRsym`$E1n8ni;qzcRhXLn!Yw&7eXH+^ zgv3<7mlLiurR#Y}6wE)TFC(z}w#*^bx~rd)O#I$C_y4PO&)(pF&ES-v%gf7^J~Ekg zlcHA5*=gZm@=*G<&1&mAzMhhoADwxj=H_&6(;1ceNk{q4e2WUubBHZF-4s@u^Y+$k zGkL>oKJPMLVX?Jh8*BB#4tBP@aEdAZqm?v?X>)*kn{Ln=6$s)t-g=Hnui8Ig0JeIFmC9VH@ zRZe7jy*c}0i^?6z?34dBXm@z|+C7gD_1o%VaR2Dc;`D-}_i8i#CUd_H-Z0JV;*IMQ=CS={^gMH8lGia|Z`L~& z#*wAV{%(6*ab$R*aROafS+dC3+cgoKz zGv5@PKWEj1oQ;wjv=meC3W+Y8?Q^-?S5-0e-i4O<=v&JKxj*lE*=wFyc%RYc--+uN zBlkCGDYljG`T2Im#9te(<*crK^*S{5V7%3ijGy}}oc8e@U$;+kiE~*-5Krc$S4MtT zpL!Av3>hYR#gx~jo!P}uX(9eq@ViC-JnrUGEIuv?zbxgy9zK1;Vs}@?jpZkwB|8Xg zb`07n%rEe@Ekop$gh0^)7bShQ7k;;U{c@EQzbeh&5ya+G^}i@m&hM1s%B;fXOYhex z>k599Tj4QLaN4$HzPDRtk}J>8(B6w$nj8V(KfOl5>+?f+jwh_o+95S>rZG$iq-+<~|k?rDqQFI~VZX zp1JaAf}^_R%}0V0ik~ge{%AB|*MU-zST{~q870$K4<VVqS z-yxCp+ax49B{F|ET#<`DT*d4)UVh`ZM81!B>+({_0E9}&w?o9xjfu;jw)P{P5IcxvAj~J-lB2(&0G0^trqclZL{VDOcn#{wyw>>Sfu^ z{QJ9)vPfyY%hGEbzMiOk^6z2Io6q8m;%#Fa7yoHcJ`unRUZhu)a;MtH(3;RuO{Rgczr?|(Rp@lL_!&HHrMZnN;q-+Ni~ z{eEFfp=~;;Ub)(QnNLSl4UvBx&v*k6HQ)Cr;Eltjgw+#=tXQSS_i0L5T_+xe+bDO)jV{uVo{c6L739qIj?0=;{DmfsVQtymJH zdNP&8z_`qm$)fCy1mnpk%=6ys|5W){+-l^@#y{z{udq{8i(t)mpKaHD<};XXztWOb zzJq5E*Z=~OVo57BJV}C`-jd~ag{zMo8i^2KJ!Sr#@icvu1yqJ*{40B>i?>O z_FP}@@(sJsKM%^9r>uH9*IQlWrR%Mw8`)L;OoEdv;*VWC%pPha@U}a;$$PcIF5|ub zCI~nro>KX8>r$iNoFzxplWw1~J8*ukq?CHyR4+w7**n@j&gTN=ecm!TKq&hEpO@$B ze*Ld|oBn>OVOgolgX4DJ41fPme!sW*iN|{DgYmmQty`_TOPbe2s+aA;fdhT&#|u2V z7P(xsUaR7z{+?@*8Jx4X6_Qv%JPtm%Iz_0U5aFm zC+MU#FtXhbJdyZ_qF$@&%An|pmCx{lSr{z;65wu&(-h$&ilQ0^YQ*#>*?q1 zrs#fISf0_7P|%pLT-Efm{nvT!1{dx#$40NN32=G3_QHvWhn}8h3atEguY6u5WBtdk z{}-K#iro8Q(V1T_tZiDJx-B*{bEw6XKt~+?%=S(38)Xs{i!^IdnqeuNAJrwPRsuMLg)I#*>Y}5 z^Bq6GF?!{$r{u`dz&`0mQ2zQ;1-Z_~+lgbH6u#`1J0@^&?il zcTKt0mG!E0@6<1eD`#>2Wm#~$qc(Qh>OViL_Ns1VD3jbFkX=zC^1k-E^9z$~r3bZ7 z<=))e*t>6k^Uc@YFW$eMdPw!QnWNKH<$@$=^GMH%w#|DWvtXaCdZ z*WsT|`c=Q&0v>oCOyRR!@%7ztxnn0h?63T>Xi448#^hCKaPZ^l@bo2d`yOvkvAOa8 zS9-l{--WDV2gAEZt|VI*EZfVVKGF5_C!1g1swO*TJ}u(?_tW&#*5E^&C(c^0mE*tZ z*z|d=R8bhy=k#?KUT=9&b>otF;M(;Ir!GuZ-0?mxw%Po!@$%5ji<7T() z;s0vld048S-FwlcMXs?j2QJ;=niSk@)RXe`Cbz~`qeV}eeAo48MMp)t7w+*tRS@1E z>w16A(j7uIvOe9{UrA3ntaag%^426qr+Zer^b}4#DlL(^FzrpFto43_`N5VUoWD4) zTo>*-^2m9ycCfa>%NyHHJufzx%=6>f#;@pp>~Y_(NX2~kEYkXto`)&x&E1?lwi*Hl}{K~ z20Zz^<`sk0D&<9IIoAG7ubs_S|M2(jtoo8|*7xKWxmKK=;Qe7%^69eylWMP~ZDyRz zxrOJ>-jiyA&$o5`P(L~SY0731flI}l){23@Pt~xVU7$C$?r93+YVqqABeD-FGf({z zyE5>(o80=Ri;CB_p4w{pVaZ0(s(I}V5tY(YW29R*ifq{6cVV02mj_4x*{wNy=2GXk zmfiEYn{Q;5RhU#R<50hR?94@Bi5vTPdmD|y#IiDCBb@f_cd^^i9lE=>?W&0OY?Tx7 zxh50OP4vGv-*s-?|0Da}&iHvdIVE+n&|;40=|9_FOVwIm`MgnSVSwR_Lvn`&S}e>P z*1I*7F5)}|Mt+(Wqp~ ze-ri)>y{%~xqCjn;?!BcE^*GetK9B!$JhURwLba$yj+VRikxP+Wafa)onjow!S%DSdy(7 zsUO4>srOCsV5xLUYJZ&L#(6?Y{Cb+=sz>Vdr+;MI$8utag6pc=JLb$i9%Ws5Lsy8c z>0O3K-T$n`O!+45ey3VzE2u_*N6^Zox=KdnYiSmG{=u(QMZ%7rD)O!QcVg?#pYN}{aWA)d_17`4 z{LjfBSJdr3>0ds1t9t} zrl*uoi+Dj9-~9iN_B$UAkIjj3JRbPx&_72LwaFV!p1Sop^i0k3(l4PWSKW%N>R(*V zXCZt+u^Zv{+bwjN`INfmgenTO!(wR!k6{ zd;601p=e#R*9%{Lk>u&;UtIrL`ZuH`$g7c(xVcKcZa!-XPqp(AzOFu|LI2w|CiToSpDPN-FFo%4-|GT zdUgHkqm4}&F(S$g%mu7&$F4^1;b@BvTezmvE7fr)%a$EE?$eK~3%|H$3)69L#hIs* zf6TocVP85|r%ZTd8|zh>7u=IK%wNPBsnQ+ewa8){C-?N}0oL0agd!7{Kh>V3WEHmV zarwzq50%X;VrHs7&RHC`*wusUaPsP?GYLEIIX%85)uj4MH(2!v`|k}lyW2uG&Yyhy z%jdKs{Of;}rg*ceaC@HFQ`sBf+UDTaaPaKk9f#hYj^UJep|E0ObE3=vmxHx;B^EFG ztJs&YLi?J~X^SR1 zOZ@$L^4M+Jxol6~zGMDve)-T}7o~|C_M~_%dt;Q6zB)kXiJ_U*qFFJA92~wUaPB*v zxj1XB-g#3_FZ;iDyoEZ$+5-8xB=wbRE3~IcnKr%hx$yFY0AKpXP8QBG_l%=UcC+$s z(ti3@Ib!|w3o#LHucCY}Rofl>bf8#-+mKV=I7~NYwzL024?VU>hhK5kGZX$KF=xj~ zFMVlu#{AiYm%52-eP1+OaA|k%nw*f{_Gw1!jHTbNC5GOp+Py;HPH9l&uPpAPHGv#1 ztMc^}ww};ZQuMlDbf#|F$h7oyX-{4XlqHol3<_4c!wiHO-Q7Ntf2q zeWA7YMSEd~LG^-8`yU4^61G?7Y~H}&c%H#$QqsL6Is4Y!I63#zot8xn#ww{gdrIQA z`{f?|am{eaOPhS@*T;9u?Pb52GilxO{-sy7?)oR*o_6-qN{vwIXWIuY?_p=5-N~itf*! zFI{l#V@e@wov&cIfr;vC$qAzCY{MPriG?kjap2C)(;8P^=1=Hbb2C@v?KZiIvK-U* z&R+E1t2!cn7570^?RhGb16ZFGdv}{__~&etjhNG_-vx^%k!$q1#8QW zpQqI)PCgiGgu*jV$5YA3Br_55!b zRQE)vhlkHgGXIn)aJ6@zo>e!rc(5;1f*qi&tc$%bi-Qw2X?dh}cehuL{5M%Ca zp(Q-yjE}Lye=*tpA9Hw?>3+HNRQr>I`0eQ>+Ul~d4<28g`!L_gk$bP$yB{0A^Ox;@ z9NUmz^H}<7{9kqZ`lFlv7(Q&^w^;O=>#p#3<_~(YrXSBMkC7U>m)$?u$`SY5b>ecV@jRd_MQ;p{Q)uz1HmkGh^L1 zWN~(;b-CAXvQ`whHgW$!$)f(5h10_;?nzkmC7xDMta3MNOu46gN6@ooi=Y-%9K6@ z)57mp9!z&&m)Y6<`N_#(i~7_suI6ohJc&uKSM=C(-)!Ekrr7T7aIQ&X*8B>F*xRz} z87i`W9sH%9RmjBbI1uW1G zNfmNbZ!OVl?z-P{w6JSSd&88QN5k*CblsU!w&2-+&DXge_ESGdKm1_Izv#)~#0e9F zgwh(Ob58r=R_L+K!SMBr75l#2f2mQQ@?p2;v7R6Sp&%EN#A9zi$k^s~K4vu9;QUcs z+i_{}&4&^V>Rj_J*>_y~zjd+t$5X4-4fk(xD5&SWzv}A7>MSn%|1bMrt~_!_=x)#v zjY+aaTQ23aA6JR`q#nKFuBIWw>&No{cNp8+zP&haM%|N%SN@$me6#lZyZc*;udnm8 zej#&a*<^Ox^IL;v%KZGpIk$b=hSVIMqe*r=0gmPkGxluR(<`@j?fR8-ENtzH-zlAo z-?Jv2H;dJgd)Ea0q{KqTw_4@DLIY1ty%4cp!Q+;PXmQ5c@THUeUu-y~d1dF>>3=R1 z8MQy<{_L?WR#&{APJlQ`8%0+yNT78vM!$89=LYRVbv!A3y;?xR*tCsthH(1 z;>^9h_W4R5!(J?(eY5@{-(#_r#hIQv&c0iv#52)hgCWC;1-oT;adF&lzwtZAde+SZ zwyuJ}^IyK?CH~!bWbS4U#TybgO*9{odo_FF(Vs;=>2qcK-W+PaLd%_xomZ`Tg&m zyWiJ75D&h2X#LVlJL{*Nn_6d{toncJ^s@iGkC)aRFS}E}Yu~n-73$Ns?l4gC+*i_7 zllE?6dW*G{Ra4QN}3+Nl2JDIUMMminS;n;c$l=H1?TKIR zT1PVH(uYD}>CYz4Qa@e4wCfyGWPu;+rUPrQKG0u#`h~&jOD(s)`RHSg8=sY{nlLsi~`P zaL5x`&ayrKww7#H+CN5RCf2we!58iS?L7bAg>lB)w;BwujphF&yu8rN&v&o*ylu36 z#e>GV<@am9JKmDp_x)b={rVRd?#f%&{J4<*;$Qw3{xAQll&1djJ?{HwSw8Fj)SKV( zRfX=Y-!bod;iSIrlMC#9&ON!iWx=-#UuSaYq|Z=Uv0V5^X4;PI@{kY9-LCCcpRZam zx8ZT>#IvGP^xY3xm{@ewos(~GJIR%QXsJi}wG)$!|2#W?_RP7*H#*Hlw_LrN#k0Bn z-95cE2Xw{U(jIM%F}IH&9N{XW;v|E;ssr%#%=zJI}KrQ6S@WQZ@w)@w*@ zWp$h;w>|gegB3eCw=KQBY~gaAm1|G$4LI*o`q$yQo{sG<@%t%K7BhCYvrPZZc;^1Y zgA1ISnJ2Nn@R-m3H%#v~->pYl8(73A8^3JzkI#Lt>l)6zTfF7KyREt9{G6XF60DWKsQ-HLvnh4A=4rLxhcp#$hTaQn z3oDyg^(shg?+l4N^X$-%w{7(qXP2q5ye+x1q1~>j&e@sSDqW_V^~mCjV%vXS7m=5< z-MeE;)AYDn*?oGmAF`f$x_jT#?nNA0c0o&*{8+Ho_0z}n>lbZy`gk?USqDJI%p2)QDa4ngck6urUKiwp` zgekZBr?rc~V?&O3#m?H_-&Zwht`yqR>QGX!fM4cCYGb|tQ-YGvLzXumj;JY2J^S$1 z8B;5B;}zGnSA>UidYXO=eqZJCkFVUbC@rPv_6`G%nI;>4Jrv?e2%4Ha|L>pY^@|w3 zl%38zu;6J;quw|67a@7eH(NSI&0aSxc0uv%CEWQlh0i*gp8I`kmyma6#njWH*$I*f zV*fu$Uv|%8EWD-Jn4;C}wN@`+?&l|3PZuw$^5I)$f8lTINB71@OeSKhC!F`363bS( zQC{)ur+o%YqT9bHzVJOHdn#e)UMG1Kjai$Ps9u|<)1b?0zURYjme054BGt_o+?{52 z&(VqNrDW6Z=hqWr*DkKBlDyjel^zPHZ3X{*xaxf3bqsiDnM&AdM8i`~CDtCP9Cez2aqEOlbS|9R^2 z_Ra?LnHSs4?3me5sga>Im+^d6!oxD2!uFN64GaHnICLp4Y=TYthUshmxZC~Y{B!2~ z9&zQCma?92kAmg@Nj~``nW%2|v27iXgHGDQ4`=;_8b7|BChD;FqQuscCbJluhB$}5 zFVC&33`-(eVqd1t+OVj*MLO^C=I1$z*WX@fdbsT-kJQ<|Da~G2=N0(g+GOy`=IZtP z5;yNosB&7ssmv_+Cr3^9%jF=s)1|DpOcUaE{t99~mn1#)aq$TqfhGHW{{8vd=d)yO zwQq^r%i3g>1?;~!%vhE1XzuP4m7WWX-S*e3@S6L-&t9`2!f)}tHA=HRIM;5Mao217 z8lo_{L&$PnT(;+{d7ifHO-xqL!zQe}SRT7#;pb06Zx+AKur=m>f5PULe~imcr{@pP z7~NX0tMKueR?w1!Pr2co6Bct=x6YKv;#1((|NpWt?QiAkw`^(;ZalVFy(v{w@$vJP zr0(RLX+`ogwwli^X;rhG|8;_wrP0}r`-iVtPW4$d;p8Iq=p!#KaA-cXas0Dn&$Eba zav@qX^rM^uuFvRhvM`;c_TO%%ck-_XcPrkv+qJsaKYRQ_@|KeFahEM~GjcVzB)9HY zcVRMj(fwDLzx@rOPCws z`nuQkL5wShyR^Fa!}wJSjs^QRd*vPf%GPwX&wy{|8SZ-+V>7(k}#zRL}$6c0ebeMiTYMbZutb_fFw>T_R7G(*z9-DDw$GUruKELPK zmBgK&t$P0LwMmH&pJ`~^+b36)evIvR!TEi2f2?$uci9=DGJQ?vjZ;T>CEmOb-`{6< zJLk$oPj%IXY|C4_E>}li;z>KbVN%GYV38CbU%&V*o1!K@SKF31QPV?hH{;xnDL(C2 z>mC=+|KGg+?zSa=X5?+}VYs!=K0UKmao5d2U;R5Bi*=e33$C6ukPc|r!78ODb*{Wn z*u;tBF7s)w+hMw4dfTM5P8KrHEIO>SZ&X=%uY4VPD(JoNZV;Jzz| zll7*o_u#I+eMC&?Rm-p4u>$_B>wK#UQcFYmcW(H2XX5k?aceaf8l_C%#u?vQq3W~R z@TiEzd4HzaGgdA%+}yQgYTMQuPK&(UgOpd?e&Apm`9bWv{EC|;dmNUk$C_W;P*Ql< zFZ$Rs!`^AXq#Ntzzt8HvYFPPW#(loWN7=dzE}Olqx~nhUe2%Sm<@uYZ;`vK}Kteskk%UU%l7ZN@ynMj;p)da?FHx zw%#hJc=Ad`Wygwhlb1gBn{z34{iH*xS2mR9gz!ujRbu!%n|WS(hq>MFpXckpUUPkN zyn1&k>xSy*@0gbceY8y!?tHn%=o$NkfS|qeO}9VZ73<~j%kq%o*F+^N9*3i~fj{+b zU+kW>bKxwblj_sYp32BPu390nLgUl6+~_5oN4Q=yB%SjRXo;FH+R)(m>-p30zNE@j z+1zKW389BHnisAU-h1C?1*go_u3IU6_3bCkOLuC8+}k7kPv~iTyP|p91Hb4y%wkH~ zxeKQ*`~LOfA-R)E5+wn*Zh6NYcl~mIGw;`vCSC7k+$UQeSikP@6E_)at!)z@NzYw2 zSzAEkgzVJEW$yo`RxfRFRC{)aC5E|Itt5+Y;-_bQo^pMUCT^&nrhe30(!8}XNif>% zYvTPYVKyc2Z&RvEwx>FrSl1V0xBObriX%QVx7ytfnv&|REV%eU+HTdn!_O`TMy4kg z1lG-t;$HW9-^ZKx|KIT!X}Fgc$>`(zc8=DxPx4c~bY122&Mh^F6TcGiP-&B{@iuD{ zpHGs}+Wg6h%`=w1>SA_S${_l8^QH;BpVsb_Q<(YTfM{cm?N5zuIg(QgFMWKVk{|fM z-8LdFGO$iZ_WwuW{DiWy&YI9@U9G4J$>q*=YSG6{eomX0!XP6QH$OqQfA=Gyc+bv@ zQqT9)luf9qTHU3PdOG2JsoD=2@57QO51hYn|INmU_gtMeZjWc#y=m%#|9x>L#VpUO zPt-3ve>y?v*X^bM7)@ULURkfpxcPO#wcD2%o@AWAd;Q+NGe;c+gffo&e;lthwd>cJ zRYvz6L=R0U$}WuGDdBeOR7yjG*05Zl4gkCK z4g25rzdKyDs`Jh^xscz?TRc{ru5K6XdA`J_qBc*?aX0h&{VJ1l)AY|IXk2aAK0n_r zYu>b1GeaNL@SfeAUGVHyM13*eju^%7P1>x{LLY)d{=SNla$RY&T*EcJ=m;~TzN3X zD^%J_>%vJ#hjStv0#n#DwAb7!DRG{%xVb%xB~rm7DW!zvWr&v8U1|V8;7_Mc6BZwxy@2~{@}WO{vp9?|#2-805O0yFw(saf*54gQ&i&tR zW*1wO{+i>L`02t0zGG@09&KGSX1{&#b$Z+(WqFGh(Y|&5Z{2cFG*9(jcrJO%iQE&4 zy|1!(bJO_dsb~8>SY#LMn0WT!E$`_QXKtSu_4UH8Eq;ggwLDS%RD3_iEvxfLQL9ew z+?_17rk5OozwP!(UYq@C=HYuB`)1Bi-gN$jWx&lk(U04Ys;4WaUzxPXc6t)y`J@fo zJJ!yw+E`q}^1H0}@x9u~6;B%fR$RB{zf{NZen-AM-=*T zFI~1~f>B7o^q_@nT7EpZ&9PZ`7u%7I!X+=B{1dd=;Q7+yO~d7dab9^(4ezEaiIxcq zuj5kLBvf`ZJpBIL^UI&!van%1v9;ttlMdKk(-KEAvyPLcIOpw8ygt3&rxePOxOqOyb4-1EccyPFIg-?{9LI{tI=>4@Fa z4$qvPzVXMY&@KJz4%qws{#mLb)_80wSCi$YE8Ma|8NUvN3bia1lQMp-a^uN#ws|af zE6U;*+=+d7^!<#Dch+=Fd9JvXm!ms=(IJ_s#pOr4cF!qNKA6O)KWYB$_*2PC*7v-f z&0cuD&rs&xZszwETe$gcH?a3lY_R`wz)tAH-W|_B2q-!65_-3NsGPBuk9al7Fcv_r&F?{KS~8TY>F z6JGizy^K5%%cped{f9XlKKZvqJ#sP%kiB62`}NG8M>zo-r#M^?Szh$l&n4s3>lW#@ zqMbIUZ1-+at13BlGeNNUZK${L{~KYOr&^W2J5ybC>E1X0+AqTXwO?PyufMbH${&f` z?Q0mm`Mvc$xVe7ujPsS-a>Z6Db2YTPb(I>i#icXn7@Hou=B)jeLtWxZMv#B(QP-$g z4+fvbEO8!=yE&I%o@80d8pPnkcF0bte5#@O0@;7F@>~u|Ycrj*Hh&!&#gV&Gq2}q+ zaE~9sDu31q6e)N-K6FzxX8$F%)h0c+q;wzfDe?(Dn=;p_>)zyVKg<-DD9x$#SUTD0 zcb~YD`xZ;}cd9lk!^?L(pZju;henLKX2JB;4{zjun^AM+^o8=J6Ma(y7ChDvH~Chl%4Jy>$7CO%g#7-_`Cn)tM}TE%h`1tm$PbVm$zv6{eIrD#@gT;mRnh) zkFgn8M7a5HRA3A|*M8c@E_lj&cga47@H;Cb7Oa%r^0nwe_N!KbyANlw=SAg3p2*dG zqVq=Q!KtFpAN;~uqG!}pG#OoI?^y6U%4OTJx!VlnOPBQS*4(bUFZXhBiLQ07y$YYH z)4E@rJI*O|`k1+|Q1Iv4@4@81f9rDhch8F~9b2cpZMkk8!njQ4R?y99e1G?T7WbR{ z?!}w0)?fMS9{la!`zieXkJ;Ya^{wpXKy}Q^zn7olHKIapiq;$EiUkH6))%JMZlx3}>mR%{TrZDsn@ z5;o)AtmhwA{@LfZ{nx7RbNhqcAADJR@z|-N?g^j2DmHHVq9-<+_3p*(N;hJzEY{r_ zQ4;=9WrFDQ!q{V7o4=N+?ppVYwc>>qx3TuEu+5Iub8CLKaah|g*V!Q-*#4R6$;tgO zT626(+BnRUnxijra@ORA>D7U+UOIQa`|M%C$5q7RRps>MR`6>zuWGmJHs^d9rapYQ z^30NwbMvizug?{qcmK8JJ$3t^3%|45|DIUB_s`e$|EFJj+kK(`TiI!@grXuN$Ebhe z#WPFfojsm*zqBfdeIhLS?S`UAz_H^Y6I}x?A9?k3-jd%}l#etuYZCST2J0h{Ms^Y82;dfiNivDtmezEiyccjoInPcX>2~7*WJh>rI z)|zFH`&6(wypYm-{X0EqYLlv%iU4^->m7T%7yax zM{3*4AKY`EyyN|YvdVdXU)x^3y|MbaMOlvg(qx%K&n_CVv2(r9eXer;?6g_^v+MOY z|J-6Vt>=7Dv&q6`zn%D>r^Mg6*6dSK5OOu;g_4$E>L%4P;Z=2q-fR;pvv_7ExNrK@ zM&0=rRrkGV&$f@wb1g6aw%Ao{jylukr)G!Nvc#;od1KS|+e%O7q#0Cl?%U>eU?+RS z+KR@QZA_7QVjtu-J#oFo-8!kHGHp|(O2i3a&eA)}_8r{x^{ zIPa;RN%W1$rjxALxPZ`*f6 zCV9o0^@~DIES{i$@*#Vb%(WjsW^8FXmVMw#p=<7H8Qr+J=*g=L?e^ue%r5Vl{2>2+ z&&OQl7Ns@=x2}ZGFBII`*j0BM+=zFI&u^@GZsT=y&V>E~eMbMyPq&D=&zpJAE7a)L zBmM69_p1}9I0YU(bmnUJzH{fZ%VG+Pb1qNHd8K)V>00WQn3BVG=KThb6Xvhg*>W^s z&h1QDHC^9R$(HqfueME5n6vibo_n&n2YbJUHTZ~@6)$K~|N2YiPHxfGTR8_k5B%H~ zncu>6Zc9whw3fT!u_1-5JGPp8HqAbncC_g^C!^>IeR0L*dma8+a#zk<7duO*)@W+* zS;sXEUpBV=OcJ)g_2AIU)mpn}WyrLY$~wIhTOrxr_1)l>=*kW!jZmiv#>Uf^wnTb3 zvnFm5&VIY$%{O-Ye+$3Q{dp_??{f3}@CkJxpz-cE)l01(vUG*yCZUrClPtDXhWz=d z;k@vFkLXdR8&P`e3k)YniB2mCop$iK=0T%uhwCd|9Fz-6f3UhW?bqGE1`l%s*q-c8 zdC4}bIsX5{3co{pl->zOCyC{#FKoRXk>u}sthDalG=|wi1#*IHf;FmNrfJBC_7tmj zy=&{bdezaaZ~lpyljSc@k>H9hy!X?lYr^%&6H^ZuhkP&HaJJxer?xtiUzgrYF~;W$ zq8BdEt;m-@RT8}{dfT&{yFb5{v^}UYQr^h#{)ls(TSwr}@86XKc+W?3Jnr4F`qPUS zRWFWz+Vkpd!ZAg~`p&mKD{j4I3kw(9u*F1Ql07eO^6IA=CJehn7q!d({c(Qp`Y*-u ze_y8W|MxZDEHBg!5}3xu#{b^k-EHr|v}g8li^2)+qM0*p6}PZDOzV4bd*hb*oZnVn zndZp6h}Zrpu zhUy2y3id8-iCy$cckhRGMU0~|LvWo+F#b$RinX$~pwMlQT+sS7^`E#K?rc6j~Thks5cJ4qety1LzD|Kf#8 z{i16x+Rr{|Q1jxk{I8d-{k6ZQ$N#={eP5Y!%umA`dESg~?%CGLNA7R8;GMp>HO1<` z($4KlHyv3T7k`RdD#KIQ+N$B2@#+WfEQ8vIi7nStcwW2@4GS{}(Br!DWQBzJ)hQ>B zKWS1p?)KweM)wu3tzoT;W?r+*t+NX7YP%dWZ^_F^s~TLDo}4`4pXz;9v|!p|=Ip#1 zkjjqkSw_&#VhhdAn@iTaPyf`rkUfs9NFYX{XlL zv3bF=msJ}=pA{?p+wO9y`bbf+$lfD%6%%UxJ^ zwGj6dVynJQ2gJnMeOq|jgS$Inf^S-D@< zWP9D0z4AZKUElYySKfO1gKZ)QuAIADUfK88u5HO1wjH}}x+|9G{<-jGGsnROC-!Zk z(GhJ*QJf2p2<50xJKlRwJOA=`-iOY6H}yH`Ig4*vQFP;rt!34o%oGRz=8YG7nHK%_ z-Ndyl;>5M1KHIi^S;l!{lh4adYqOr@7RQIqU&)ZRfH`B=!eig_J=#C6Ex1!y67wyr z#Qs_O>Llr4{)OBP9y=rxKS&s-xp;m2Q6!YtcE7czUnox~$8Wl5x7Uthl^-&$;f~w3 z1f})($OwD%1f{E;kkE|Wvvk4f(7m1e_f2HlbJ|>dR$hE`3G3b4b6@;B_WVk+?gf=M zxo`I;w3;CnHZ+c(5sh$4CK1uWU-}(POoZs{7`Ty_c z>;Bw(f4A?-otw9F&$4c)sc%e-n5?LAzJ5B#)~d7o>_!fp?P@YNMPdHbx;_CIK9qMuy zjGawF7SCEI@bzkhp|O*XZi&5(Qt+CjIg)>acPU+K%#AAPU1Z{M@Z!{>zE#=xH_Yxj z&=Kso-S2;R!wSu%mzEorWbgW0aHpW}k#K3xf4O~m`_w!3ickE+6`a4!@uUXJ+^Ysl z&(!@fbym_cun#D(54hRd*DoOH5wL!71(WsLGM2AfpRPBTS`nh9@XRyFlVjA6ra5<4=!!c4%KJ$F0GryT_%3_XaE0? z`v0EP|9Nb`uKwxv`rq5@buJuutJn}5tehhFpVR$Q^@(3aG74GmuNs^(vunuwbAdni z^PI|?Pl^^ROpM%B=994Np7v|s%qebb+b;SxzcLQ$eU^Co#D*!H(%os>45qqRr|Va& z30oZ~{QB(G%(ZUOw*pz+%w|n`)#V(Ndh<+EcqE_YsR>-ZteYnSDs``BH z*`gzR7OXM(dHtwBm$t>Z33LDEu1kBeMJZgQ$l+XR=#x7e7cW}1uFG@sO%7{~#~bec zxa;`l-`VX6%@^`S0;WcBFFG(=?8-Ub{;90yVX@zq)vZ};&L5xHeec2V-fd?XQW(=# zpIdxSa@A*%=UmZWwIa)#-oC!I>U`|{qf5QT3qC#J+*9@?bkCnp+!ZgEihnpXQQ6|x zt89znS32urb~Y`2s(K~$%w6urK?y<@Vbv zIVZCOKPsKOu=seD(Y<-`HUD?-|C?U__w1{;C(h5^ad#Tijh)5m_MHFqEn9AL@6_2; zQnXX6=X`H=L}QQ81@7}4n{#&^$hrDMvH06AraZwr;a$pHGHu;@*kb>DSlmn zu=$~*&n_lv90YLmWpAopZXM_tPM&oi&oFR`2<@V5OcKZC9O@Yku5}!^ zmp;jvTLq4@-0DAA_PBX=^go~J4dstE#NIXgy2Gq=ziv}}{*~69ozXR^>JQh2gk{Db zesznB^T(zo&(hM@KRm=L^htR6hg07Ak6$jIe^9vJzB9l6ccIPKCzmT;9u0rFb@Pmw zJN>#AYQ6D1BOdu+(}PAwo}Rp;4_=7z^z|&hV%}5pUhRp;i{PI|J6$4o9r1KkQEpM0 zCUuc*vBBf1D+05me*F~;)U=!#w!zq=V*a02|C%2+p1k|}T)zI#NBNr!4|6peUcP*3 zq)}@txVIBq1p$q(Eyi^Aa}rcc?x(_2gJ| zaK;l4)me@AVs0LH%6+hXb##dG!d||oY}tucc_oSgA>Wu?BsofCy-%DHc5yb`-JBH` zk(*xj`Ns9{Qv=wAmJ9rLa0{JXQ+{lk;X=O3L^ zpD)<`?@h7(gBKUCzx-;vgePs|o?Uup9OYu0i{kCsjvw>bpuVv*OMKhA8?75VWhHJ} zH7BpC76O{kd=5{q)bm`p@hCKfN0N=gD#7`cM1+ z{@!_e;!62%Wzk#?zZi4APtUzp_k~})%|qru*P=fQ`LndyBqqP&4sK9;n{+$Y>8bRT z2QD0nzv8T27`CnBe4r3;YO7*sC(GK%%qi7fljh#w=ziS)cE*Ri8r@y_rEf15-urQH z2djDDruV5w4_AGCaLjSm#HD6Ua<yZ?Ohtj_!J zmu1@?-1YbHi7z|~Gj%!kJlETwGKpo*x00rH<(Hf_Cp*miUL*8$PP^Q#(?40f zN}^SCC-_$zd9+PsDz>zmmKoBWq^Y(|sNdODBY3U#yB9uH>#p#Ma927uGc*5v@%r`Q zg#Qd|RqPjT-%n5Fy2<(L!1B#E59$B={QuefxL=R$e@?!h=f19P#_hG%v$xp(`EYpW zzoPpSTaw@UsM@@_;U~U!`x+_jFKHYSXSTCj9n!jXI_X;UTt<$P;`Y>)EAj<6u9mxB zzjV5swQvvkJR@&Xu13Tvuk##*fC*6B_oI2mGmZtNdXeDEG{o_X_{w&#`$9);t+n zX{qrd43|?2XX^ZZFVm9zzbbca(^b_?FFt!m#6&0_j922`uQZ3N^xd1wFZ$e<7O7MZ-36Y$aH((yvT%`6JIY&Vw!eE z<%A9AJBh8K`mCEhcQ@WuGk>xD{Q2;IUoN`K=k7ncX?OCr+d&LlZp!~Z;of(_)N;m> z$y-W4r}gmhzf$af$P>2I_3*`@K(7G*${?n7(UCV_8HeQl?%F=DHQKb&;?M(a1D~fe zzI>h*Br;cR)@tt^)&J`n-|!^5ySEwctzQ0W9XG$~KjG#NKOU(cSh7JNm?81j={=?# zzi%J9Zocf~qqoarS00F%b>@2JkpukfY04b79TDNPJvSc|xlpnwVV+>ZeU3W!`SGcL zA4hU87O^P3mbE!F|J0AoSEq7K^Eee3qCw87S?A!FVPODiZ<|?{9kul8K+PdVn;5T_S$7gl? zdD`DfP8w@-x^MQ<3<`N{^olE3F(Md+tj|to+wl`s0JF ztn`jp)`tGtAI|mO;vYA*Og^xzk5z>&r2Pg$!JXWy(`lw)=5((Itfw_Gf% zWWq#+E@r<~@Vb1lnCI?w&jaCMQyk8p*Pk#!fAR$Vpxm!j-a0d;gmoVf4Dnm8 zB75>?w@&$+LN4RulV@D^ST?y!-NAxsj>fgc3pZcr=%`<#W9Xi;BjQXc)5d!-4oA1o z%XR(Bv#oRfiqD%TUih09+A(eEZ#Rb6%$4ljRbD&pE)gmaELykGAoaS`yVatr*smVZ zlC%C*Rr;mnY2V9hJV~eS1j%;1@!FUa8NYrd<1)^o)^1NHr&|>)tG?{In`5G@{q;V7 zPjBtDO>1tv+PQh#?Jx%UUl-W_DJ53V_Yzu?{J;A8lN}-9t+OJ2hdf)S8QZI~Q?#sf zV_7KEx?|?tyXUO8_Ouo6Pr`}DRgISOoWj3xt}HLrU<_>Jbtm3K}F<=u)2rC zr(MtIt*uz+;B-#sG|R)#pPL_*PiWG4ImP&zHOFqA)-ab22c5*L=a8*Pb+A<9pqwE4AzG#|Oc|!Tna-s{6N;7dZy_3(hR@Dm-#C@QeMIivmj{ zeF~0VXtDGYX_lrQG`iqC5WucZYWJ}hYH{rtex zulH(*$X>OBTSJ@fXd8VkPpuUEeEoUB*H57_7R!qt>hEuRKEImL-}bA{zRz!$e|Vd3 z+nHbcTGQs|6+xT&C!%v~O8KU*JCo2VrtGimF*)FS(S+P2ncHQ4iNC*?l*!*{*L3m> zZt25zDJ?Fpuzc2p(zZ`2gFT3e(nC6CmC-!K~e7oYnM7dix zd9U_-4Ocg#h%FSG^8fv7MhPK7^Iq%5J@fa^Uj6RcwQGSM zl|{cSjV~xXOg`k@*ll$|Y$r3v-%{hc(=6>3|6<*hCsv&C*KtvgGF_D$@%xTdd)}IT zci6QhW1pW7n7jMpl9;VsTnFDTeJUy$u*v6IRp+;@Q%i#wUats!?X>4&&b8EsMu98N zF0obVIa54AK_gB=>ezw{X-``snp+*#n3un)T(!pH!aX-zeD2C0hnKDC z^R1uoC3w#hXe=rH-<;jH(?iAgZyD#7qwG6QnZD!OQMNR9>!j!Jh3`2;7m6FCl$+*k zm%YsWXw~Cu-N%1CVl!M7(bdIR@G!{xoPLVztQnKmPMnd*@QL?krBxoUsYZ^mjKs`xrvw))(UtVz>M zH@{9QephnByyw-YW8KeRO+76k_lA9UWKLq$$*d2rKZZnFhb=p`=D;00txSX5i$6E6 zO33y;w_EjRex8Nm>Dbk)BEM`c6?#y*GH!L)wNlpGT$~@3(w?WC5Q;xEb94HKUmG7+ zd~BWm;Y|7bqr&$qrSAWW-gd|T@yFxykCxA`W7OYMA#%Kb?y;Yn#Wxnz&THAP#(173 za;s6~`-dObO5EQnY|a1n@H^+<8-G8jd!w>Ft>}E*rhC=~ds1bXXS-dvY~8?g-LYV6 zqLylyiRW_z?`vkqTQpNHa=)2Bsr23H%9OpaU!G5Tp}P94=9aiy)fxH|TlJS*35lQg z?(|Ay|3#0wx}qQK+v2o4b}!edN!kbfJRC!#bSf0%1+ruHreC~$Tl>k})VpbGW;Agn z9TlD_vnM1hYRb&%6T4U5=-PaZJL7qd!0yI5rmt>Ucg?a9$TOKbeY@*}8UOdUGGuXd zd0A?6m4+QS!&2IN?)y&e@WNMbRAuTP%iOalWL$nOMogsi?=Pj;aJQU&ax;$!_sTk{ znQ^^T`Q#&a`b(~-RsNUgm`-JuMGiZyul4D)m8qXF^-BA4YnUT!;lQ%RsYg@!kWn1W#I+LX+ zGV8qfv*(4iWo+Sk@gWobJjvYi?Utd?yXhaVOum2gvC5tMzjh!0s4MhAeg9vcd6l1B z_k1~IILD?=Y`Xrr#LA6LTHhrmC@kgTIm>QnvQ1Lhx;!E4eBPToyTvcJ^C$hfp!nv- zc6s6I?+H0wpC3j)*}F7IpVNzTCQsxq7q-lPW?#9THhP;>ZfJfg-^_E-c;1`6R_6C+ z`wE$aA3FQKXoZC-tpO^IIYf5>FqjA)O?1zB@#n-D#Q=j?ruk2j)(SU8#jHw7OJjU~KK|fI^Yf1-G;f8+TYGl>6w3J@r^OS!iuW^UI#{LKRK1%zJ?_8_gSo$LHfxo?uwfO7f3#)E^6M(fYhx7G z8?$M>o0uwI;cU_?m~hCm?kjivpF_p<`I>+2@<6fs?vAC;ukV-nVnf^V?yS4z%%w2Z zujR>ARGDC)UQ@|!lM~SpPmk1qV)F0>--0zo6elK|1C7H?o;Ka zJLe}k$R9NJ-`k;les9~4dt|Mh&{+;ZOc-Q<|sl=pY7w{Wul^66Vs-c|gxbIKI4K6eskBX|KLJSEKsVG>%r)uj|~> zZg!o$e$h#<(K?!C?$njXCpSfGRGB%;X6;UvPa2aHrnh)6aBtbYJVxYKZe8zMo6ibH zUw0~*b#m=qbYxl3CAW>v_Qyj@g?t|ConBz=oouD|)AjZl^OnA+6NH{`xy`lH`+9nK z;loR&b1W+P*6;nN);C|}O6i>MlUvrr9sk+=yl|?>_fM~kv|4WETtEII!(LIC`{x|x zja+&fUaB%dtLCLlFe-WDU;o@wCpP}TL*{nV*;8c?RU0~Pxwj+fqNmaOM75aPGWDmH zeBoh!Yu^>EnYZxk`+Yy2>hJql*7})!<6c?T3*H64jamN3uwKtJ{PxX5b1mm9*9rTj z|J`q3IFsi-KX~zi62|s(%(K6@TsG3Z+Nu6CZP(ce{xwg2Doeb0Ju&aV(W9^J zFF*glg7dq#{@$+i`Ib$~=PN{sv+O=@U}o8xYh5NJa=-cH?r)P8ygz#F?(R_EUq8xtdioZgS-R?}UCJlh zB?6zFrXStQSraD_wOn$ZdTeLp6V6TFFIZ|XU3_YrT+_>?J=$V(S*`sK%~$81clGI- z7>UExL2I_C$rWyy|5nRUWSv{|^5YVVCbK4srI!gCol$kTHv9X$O^>doXU9FMV^_0I zU8b(r`RqVe(DPHdS2K=Id3-2R;DtoPKD}kn6$5(33`9O88g4nc_O+JH@lX{bAAn}lz(jcB396~F~TEp zg?<0QeLP)Dcp@!6FSRLJw8pDz&D4F>6$^AiUab;4Fk$P5^%rhRTFshxR=MKALiQAu z%GHObc4s}YIsQfVZ}lu$tM@DSoGIM!wDjv-nT}_cecSwk*jAmM;E?qpfB%oA`msOT zg|59nUUr)+;q|q(EiQBaPxDK1DpApVXQZo=w>KnHa<1~V5BJO7NXInyYRXwJW2l&X zU9~m!#mdlEs(oS!&sZ-o`A(KUc|_XZ_M=MV$LAmJTt5GxQs~EG_kQ6L`{vUrhR>c) z4_s?1Q1IFya<`D<^~SS{C2pGeiB*Z0y;Gn6`+(z{d;b5-4u0&6y)1EeU-P}qqECGn zYkcKZaKB~{p0Z`~WQHXsEIVWLvbqb>J$HQGGJVpvAJ=$}?kw55f5OBSmHM1z@ol<0 zwZ-h_C%j(!ZHe>>j$Mzv6MKFzhwKw6);V7uPu!g|jAHwQPEweo}wG#)ZE(mDfM&Ts~i1oM$fEods?CoP^lF z`#ri4YrP@+w!ty?Uxrs^yZg_(z+I~wUD9_a{HC?Qr0EW`j{FIe=B$d*ds-4{slDD| zy}hW!mfWLR$C=Z2es9$N6=N>Ys-5YpuDX9ta67M6h5p>Bht!?b4vTKgTxM{c(S5R) zTItTP6RG=u{M4^W{PFwXElSurzY zm;QOQr)Gzt+JgBZf0-4RguE~2Jvwcv?%c&Q@^kk-u&6rYwIJf1;z2)8?fjkf0<+CF zU%l72c6V7)Qk8h*o6M#s)f=1Fe4i$3ZLlv{d~f<3oj+-tzBH%&?ecj3Ny$e?VP%WZ zyD864GMzTM;%B9_rjl=6s?3*33g18J{=8LN`D?eOP(|B|H`U9hvZg0-O{)BKzw}(p znyt?yw=AwK@9S&y_$tMI?MrUZ^rfG+%%5ZM>Ddy_)joOQJMSo4FHhPz*>Lvh7tfYW zY5G?tVlY*OP3ho1#}m8d+;>YpQfgUSldG~d-GX1(X>Qs{879+Wg$GP}+h*@7TDP{g zMsw3dHg(hg5B}^tEmZRK{tB-n3HCE_Ty~*zu_(*GINL$Ty zt(|4Yn@?Mm|C8#QYtcVF&bn1R-n#MV)6gj8y$_bePm-Rv!{1dEvO`_o~^9?w8Y}H+F1(p0O}+>B7EbrY5Un4&9rUujfA;y*=^rHBO#M z`(xioFWEakrbTIz(jCbt0m)qnIjpfO_5F**B|X)h-#Qs7RJ`-3+wBvy`cKZL8!{=A zA4CbcR^>N(Ckvl?WW2@y)rm?c_6t*{mX&<$*<|)=-)hN{sR?S42P_Xv^YNHnIIrfk zQ1Q<~ZzIQI*7Kq+;%fJD{8(%zdaW|cxoaW1ZB^S}p^m3XSH)hG-0Lk`C)(2XvgobT zwxsZ0rs7G58Z*{dxIeINoL9Txbf53ypb(AJe`VpJGr0JF$ga^ldoiEm#rNM!Qfh;? zF>)3+R2fgmVKkTh_+U!RMg^~<{4rN%$(r2a-IbfTH%!=m{%(Hpb@7uEbZ_RJS-a-Z znWNc{>|%D8#j-8o$WuP_?tUQ=i>MEJzlQ&XzF$U$43{dJUM>u)MM`Ob)H%i zF7IxwVT*QSGcYymxof?xYk_&xzAZAFCr;e>^-J-lEn+s|3l}LAY|*~*Fy!k`ujPN$ zCJqXRYyIbh#U4CA{Fc^X{r0t!s6c>|n9_KKIGD0QaREmUyCn^H_SOIz@@JD0ej-Z_qSZly+aWOXx^md<(dB82e&3a0j{W;e?LVvW z#K_6>Z)Gjn&c#u5&VJ=HQLC(u~w`(Mo7+}tX9dwXv}#f~16wfzVDJTkvp?d;F9^4Hk7B0Xuv zz6m*Q3mJnOS9IUL$y)LF{Qpn-|EF8e)p?Su*>LjYTvaR1`2{(bFXu0uzCc4iL4Tz- zlk=p2duyay?p&fF?X&!69D z8CY^f7p&_%ag-%S>4oj7Nt+*N8wrYP3;vH@JX=p&j_dnb=H+`@51P*9HFOL-QCU1S zVYAVfD{Iea3UI%3`uT9%fg-`8`y5p+s(E?7w(c?4cC*IH`@XsHWU{o}?DMTJ8d~NW z8_G7GWx2VwPhhp#i9_qdPI&3-C#SA$yR5R||Ihq+NACZ-`?=y#=k$-KHWpj>3+%nL z>BQ65$B!IgxmWrBZpHs<`Gd*)ce|O(bB~|vRLqgondCif(v{~wBINnr$WAZJ`~GhJ zk;c2X4QvhDK0b8hxlrnP$@1ZigQu#Rr<{>WTetp!*4yjiS`lkkSqX+)$rXR_j7;TV zlsJ}dmJ=DIvaUs}M<~Gc>62SFKOgqjy?LGQzOQb=?c2c&v$vbiS@JbnWzMu$>!0oW zv+2h&nV7DohFO1%(*F8pua8uiI6>P->KfAr&$21~IgfYBTqeXORJi zk=-0-XV1=At0#qsReUYCSiu}9b7`j7=fknV#S0ccU$^|#S zvf71ZQyRFotlU!-t+7|BLhfX~fL6xog8Pw$jOMw1bxSH9T`lSOta4|^UQuCEP4WG#hwUuEDmf5Zi&)&4n>!{G({E7PU2fwNceflXH6CJ01 zB;aV)X5B{X_RoJ;F4^Gy{A9zE;w{|=Kd|_&a#M*m((JnLWa{v7*Mw)w4ut5evJ?2V z`~Hu|`gJd(x9f!1FM0cRC&T4nUZG3z3t3|ezL+Ga9ePs5@a{-(Xrq=?PD_3A1OLEI z$Dcucd=kgXP8+b#yxX;y!(BK{>-(XrmAS`1ZV@e6$oet}!aRa{Zu=zF}MnCq;{FE{`5vBt34l%5M>KP|vjx+PzyVN-I$jXiw^?-pvk zwXtooR&@3dS-XASF6EMBzbo@zNtZ2H@qYgHyhTD^w?8tH+K? zwL5m{PY+?5cOmsc-#TBzaL=HsPqlJZUu?EJTWjfiJYS=%{OU?|XyqOahQirR_Wv(U z-~Z{+_i0Py|9#sga$sNW@0zB<_sfL0#co_{!IZsI$zZm3HtT{#U;Hc{ozh_3+NYYo zcJaTDQxaUdb3I&km%BgT7y8CQo4fY@4(>HF7Q1wepU(WOKbd!J`N}10%U3EeooCVu zt_tq@bNNfxZL0{$smj^ER!p$n7G2S6X~N?+ajN-ewj*f=E;L#*T@E&y79EvaX|w%p zXMy{a_`v=~`EUQ~^IxC39ewcQj-;y9=kLDRod5No#mQs!Z)ZHZeJe^f{_m^$Nqtsk z63&PBJ}Kr;Dp=qj;D7qMA^+MVp==&gm8!ROZC6<`@x(+2Eop|C#+oVd(=^!X`c|I$ zVYRx=Fm#LZ(?4QP{juS1+x9Qqefu)Mr|XXM{Bs0PJw5bG*fYmdw#et$oAz$%lGf!CvElNR&=-Exn$<-+_PYn z$&AiN`8~WXD_7rmT=943tfa>tFAaZxh}m%{%3^vruaPaw_ftpb8O%CYS2=A8!|zw~ zn!mTv#b z!({3Dr1ZlIvokZd6&Q2pZtG>*71)ulHYYY^<@TR*pM5s}eQvg`czxVD^@CqKFUq~S zZQORUvyO*XBxRj)v6aplea(fNM3y^Tx_H!oowD_Erk(GaTIc^3|4|pTyYUg1nvLh_ zLayysb0%cZxRUK19Qbm}vMlHAhc4CLJJX`{?n=mJHj(p+pEb|K%%7~~r{*YV`uO*% z6J6Kli_Tc4T>G|Z!L)Nr|3BBSdDvZEA}Elb@6GsOTXNQ>>0(EZ%N%Fr%e&mc$z7E@91fke{`^<+SX`dg!#Nhw<;i=6CpG!1hs<@EB)WTT)1h_33(vS*5>yJ& zG~PBv`_%Q;*ZdXl4y-Ck)l2Ton;sUnBzbZ*>kskG3nzR_Syrw8dBPPrm7Tnn6R)q` zzi-K;$b%7$FU3NiAN{^|Ys|h6?)5*~>vz)u?}4Yj|QxK8^Kelop?SCQHI z&AcGbEsJJ}y>8oZBcev8xP=3TrN zTk(1CgDrc0n?3j*UHh(Vdvx==!Y_h<<%HRH+`PZvkWJ9`_}xnF)!ITO-s!=UCOuAw zj$^A-xfpz6!I5J19nKeno92BIIjAmNqirwy>iuMSzp~j!HtM<`HhJV5wC!pY_v+WY zIy&pTm)}41N9Nfx@g<_W?`53am6#+VdL~r1NA>RegszoBRr8p$MclG&q?INnT+94g zzBHgm)IrB?kwe?wh_$J8|Fz?PHe2svYuLVhErXhx8q@hwyK_^g#gv^?I?{Ci{{8l% ze9tw-aZOnzlQN$dCElz4!kONE?#`c}8BvWu*G+{M!3n?%0PD0$r+V-98;h%VWaJm(CPREIy=kP%O<- z`_szBI~iUjX*gb9AHA&6<2YxD-`xLwvtG;=VEk@VdjHy?^;R5TJ^Vclbkj~i#Qo?LR~jHP!Kr|jAAw+FAf37^hRIVe88;ODK{HzB~$6PYmWI^Kj%BPD^us zC|1-NG3|_xM>={6Q|JF`eUn4@#=>1Ed5&|4bo(r*{q*jw8@G5@e8$62yL)DhI}X?^ zPGa?OSa>5#H_)hw&!l-`kolh*VF&G3+&^}@*S}ldge53ypC*eD*MsWFd;fPa?TEba zZfz3heeHV!-UTJK*Uz^6PpjAe1;3V_Hdc9Zz2NJw zJy#xF=Qw4|FTecrjs>gg7lcplaYA<#KE<75%He88bktV;Au|PKTkMIx26%Sq-V~C)w8vaeficZHz~l`qk-j9D}!G{K#svfV>6Wo;UuA|!tLeP zZ~xA!4xS#i_j}ptpXtwRpNp-1(o}x%XMb(@+k3(HXI3t=-MqxA_ub*yC%dxOuwJ^o-B-tnAEHN=I#%eP9R_IkSsz_2#q3RD}5QT$i5r_FU6m_dIOF>7E7J9_y@5 zT@ks-F?qu*(*>u}7p>g8g|+47(_hy<-`VTnn`MUS*#{H%{_u{mFNALYlV%mFS=bnHC zMvFL<_P>Ao`l*i)+X;Pn8M$eh&VT;wRIyUk6@7Vz`GkvdkmF2+nnoFsvKhMPKX2x` zcrfMlj*HI?{{M+zHesA~X!a~>l zXR9-+UAY!4+jPdW>5raJg8K4(GA!GX-%dz9jCany;iN$>DEMu6KzVTso zZ92E4k8OMYt5uVGo|pde6>{J2`9gzL->t;6%Tp+8Qoxz^ONKjt%s3GG=3A2E&ZA;= zPgbkRX39iJ$;@=Qet_jwbXDQEBI&+)S;rm<`&v}IQR?5>yz$p-LtFZzrC^U zoAxa)=U$BVzV#ojNllci@}8@+MOP$Yb6uRqi)}Yb_lYdsaN}E0mSEC-VZjYMZ%V$5 z@j34?`OHLrwv|;Oj{Q>=J9oKpH!Hr{r(ZVr;_OzAMfW$)*s%Y@)|X96M_C2RuTJ>) z|3?MC(&~#vio9jD@;}d&%l(Nrlzkzp*|4YSQRMW~f0sYG{oA7JoPoK%zW7Ybn;r^p z*Y19l=^M?eS60Zbav)9PwQiFf-V?lPrA`TXqHJz2sJhhh#Cd$w9Tbr+~>)yBiTX$`yUhdhCg?0;_r{AAc^s#CRlfjxQ-haUc z9WLwN-@ae-pz)h)`7fs)W`8{)h3Ie(tL{N=Oa&SkD^Qr>)@cGQ4hCeB5%Q?Gk|+FI}3Qf3dA*SA`1 zs^>VHyVs(09p`a>(}y2EYFGSuX=U^8jik-i*DQQ8w(XOj>pjT294a#H>EaC*(y2=$ zHBNXt*5w&}Dw;HL;fEoJ6S*>79=j{7T&JtUl&H<9vqC0hgWjXB z(qc=N-1imq$=`ded)l_TrpLM#MQ^y~-7XdKx2t8@U;Rd5Uezy&Z|`h<|5Y+uRsZH# zcxKVUr$TAWe`m~nsSsZ~iKRk{uU0HCnnQbf$U+VKZXGM(x*G>6E8DCtbgCh)O&$EL@(^ zbUd;4P>*GyjtBRYl4*6{?)~5KJ=B_8p{n{Q*Mcg~)HdJC_f9lAgfYa$3r$-WA$V?i z)a|BeccMOjS}eIYG~Yo-Wybe{DPN8|cx>et{28$#`|sUl4=>KQ?Q^f+*sb&1GA1{} ztvX#@CeNCy>t^o9L!#~h_6A*7Le%&;Cm38le_7dp$v7xpk5$7evWWfs8RGyqf%~&x zhz0d4M4Bv{eCbFk$AZHg4cnDIpVwRZDzgpsuiw1c3|4s?1@t(`Z+Go zE6t9(^S^$nlics0t?#yPdSLYP#IEUS2UO=6Z53G~I?-^AWY@&M8h7(rL=SLiGRzB= znAa~+syprf|Duh>g(&hhZ^IMOBRoqCDKr)}1UoUfIFIfqY8&z{&I zC2%)%t=MFds98?>#dRJMI|W<>Cuu~i6xkqFCooZWiC4|b^3rs_#pMg6{eGLol-Y9? zaqfEle9`XplNEjoxUu~T3=VDlch4_VdfrSKcMSve4Y7uz1rxLs)E{3E3J41Ex^`Rj zl;VMsBBS)ybNy3X!pqq&30*e0WUZ#WyT;Q_)nm*0n>RHVN~SCC$UGdSIYnst@m1m* zg1S0HKm9zozO}CJUfjH<4O2=}wn)DB<2BwouVdy$@o=r6e@T186>J?JKfGx8a@&@f z=Xo|vn4vXOR#uYpI0H{`cf=Z}Yg6^No#lVFH{krCLz!n^SRDS!rShq+c<-yMV=U+W zw(NeK`u5}0;!-8!q+&6z)`=1q3pj4qJ>1P-|Gi!RVcUMKZQ*MeYV7U@cujgAJcl#k z*vual`qL(GAIP09Xt4W)^3^kri#AN#?Yro|je=6biy7Q429~z%D_=6CrSX=Od^`N| z)1xypyNfQ@a_%cw8ZqP6DW=O0*<~$bf{TqEKl>>zc+fWGmT5L;SNx%8(btquzMiPH z#pTm+YwLB28r&u}r)5@gbRM7nb7@7VxNoAT&8Kde5`G8ns#9lJS2v38z00g}p)6)^ z!ORwWInI3*lCLZ+ZMzR1DZMrEB9j9^PSL;isCWU%TNd(qI#_ z`U88Lk9ZRh3*&au1SV4N;p_%Oyc zD*ATj#~l-9&THzG4&z)q#mQyYtIYl9SfgsX#oo2H9NTsMv%Rpk2HT>eQ~nnJGmcMI zk7ZxJ|CpNE#S1rj&a8=fV_(3bsq!U8AiDgYQJ43r3uS9#eb0LOIwl7zdv$ZA2CPUF zOg)h(vP@b^f=tYgTQ%eeC*# zX_LJE?K}U3bHd!qR^?u8)-^g|3}5yKm)re&aG3vH-A(Zi?zi$hR{YG(ue;l9cK2^! z``p=$mp*LUzMuE#Q`exA>5f&|3tMZ8>dq~@dhP59^Y9wqvn;75Kd%0&3JDFH(7I3O zUs7V7-LGH25_KJCpmchRxWCe!G76V)N$oR|eL`uD|^p5BNLTns%<-SZMm<;GSf*km7*4KsBK~c|v`X zK0Ut-P5rn#w68n0UGOoE4e=^!3MgK_)W}z2ySBQ*#p7@G+K8QAEzxxNBlqjog>w_4 zqb+QgMRWFb9MA~j`qy_n`|QeUQ4{9SS@NqyXFeCRdQ$fxW%j*&g;x6F&;D4gGc!s0 z`bkR0vXt+q<<1ixo=1ewzdbm&{Eb7rzr9se^~TCr-FcN&;@5Jb7^6>gE-p>qQ2aVA z#-_Y+-BtJRD&qb28~L~2-N%@xxwkK(Ub9c>;Pb~D3Qh`~3;1HaCLxMtXKT-d&hC&u zjW=6FZ2J3nW_~~L$MwsOZy5{2pWe?367g^SbpEV|s^)ozgiHQr~FC z%@1rNw2+RI%i{vzFedJDqi> z^0(C;$Mv$evo|K*_0owC>%26HDJ4Bs(b96RIH!zXdBw56PE{3#H&)F)Yiv^+Hb4ER zs|Aav1P$cI#TW!$N-U^<59Wd(>5)Iy&3d zF4OUETGsZpgvWT5Gn0jdi45ltxApBSj!W#*-8j#2##>D_2`R1_^}%oN|52}7W}{Wx z(r0Sxou?967H7hF&tl0ERb^{y+18SKt*tvX)E-arzCLx{G`%m0XY!8Lsw!$SY?^4D zCH&aLdi4+KALqFE8zP;Vv^&l|KJccmegEeN<*&pAr-t7xa~5%M4V{^|-O?`Qa;#MN z@2Ah7o?IfDofv&N>*>tQK>l~T6t-vyJX&Q{$8kq)&g99y>t!CYCM@#3x8vXJlM)uM z&MjGxmSp%RzeIMf%aYQi3~p|mUGwdfb2)8z+qRl*KKAANmq~|SE@fYn#<^+fj9K#p zjc3o8(PY!K*ZZ{g#=^HzcQ*bN+w*UoY{ld3?T_ExHc$LLEo#lPO6H}mCr+Mn(Aw_2 z`=r$ixf?uc-46<{icJ;}*JKSj;Ia8s?c%(H-W_kepWF#}(K+?0&Q6~gHCs#5?u8Ex zk5t=Q#FmGy*nETc_se?w&RI)UU%ZiX@Xj{hY1^8Sk)aqrcR8c#gGW!zLZ*mcu$`|g zU*{siaJe`&J&nsVOL?bus%k6C?RG==g2&Cw@5%st+* zG0>x8p6hb>{48^@`XG!yK2J=E?ImUS9Km@xO~l#UBR+?shi(ylKI!hY=wb`U7H zZ2IM;yr5qS$c41*279jVTMyO5RK9)M z(`N@n26l9Q^!)gl`}3y2`**t5oZ;atGBsvW@U}ED@p_)o!4SLiQp=)AHD`Q^;{Wd` zsoz#w(lz_=(>-tB+B&UWJDbz-@TZTx87u-_p5I%&>lR1tabDKoU-(@?^GW8edzMa$ z{}#kot^09PUA1ze>$N={BH@BNC~xgT|4Fw$lm;=Zf0d|k@iuQD z!_AvF7g}upEaw!@YIWztsS|FIp^Z9OdjESj7OTZ{)vRv`+djwY*D3Q^FK6uhtd+o; z#&It4@tTl?c{|rMdkJ^XyQus~&ev0KqpIl}L&bBRFI0G~x8)wlwchsNn(XY2wX20b zEcMn32#V=A(^FDWYnLbybo|oNn#f~;(yMYKPqi(6aWI5`$EzQcw>_JX)Dt>!%L%5y zNT$!1BIR1PH`qD;mYz3D+3+44i?@ul3oE7s@z9p|XSPxO|gVo}fa@lG*E2*fVFk-Z0oK zwMaB%Ye0I^r1!h|Z9W`0(>r0c{Si>H8XX7w}I-Z8FB%;@DVVc|U;kNE;; zdsm1%Kl3OQD_F+({8I6^%c>jJ+&<*tBv|oE=<~+c6A$VdaXZ~;xLRRw*We7Js$;}N z?uY-TSF|Y3l#^s+o4Si<`F!7!#XU`Brh0bo*zfi_?8 z(uxev{8z_CIlh}5$(F<;~GA|6)=MmaFWv z;EN61C;hBskwbv^vIh$mW(o2LTefN5Pma5GhvO*!3lXD0(~Bqb_@bU}b-vd8&2{~R zc(&6~Q|<}PHe~P7`hIoR%@s42z2S2eKE5u}qC7FoYtp+Fzvs{Y`+f2HZK*=34x#BY)oWurjckdNgW!yZy21IUkN$PkfW? z6u|$;CabIebn3Z>#adcLTbFy>&R^nbAu?CJDM&Btqr?nT%>x#>CtP*?guBjNtox%j z<$3Lor(&K`9d_2%(vyA`nN4r|^{Y(McIuQz2bKHn`o64@5xQVe^D~=2>9nr2q4)dW zFW1jIz*l6*_UrdW2c|t$uB=v8RUQGRn~E$`R^AS9Xqq+Y#i5gvr*BwRHuJ}c=lXHS zR!udPkdaV4_{O<1RZuTJE2#EUW~W8P4~?+(k%~vXzWTmhp_qF6`dx3PMauL4JnVjQ zU0n33_mW>6!Z($44f+_}tWeShP=ix4l;MeWb}KR&rLPY()i!kHK(uw(1p304gE-tBxouc>1C^N!2U zPMtihec1ZmU%elf_NuX0tB6Y%f2d5Ic`ckf?reXT`*NY=Cikci=k}cs7Tpqf^5Wox zM}?DREW@|l42g?4=F!b9KIw~Gf16uFO|sCArKckkb_bTfvbp!;*X@FiHQx_hP@jbfH(;s%n|B}1+_uck|do)Dn|M;^1!Tk4sttIO0_to5Q{;~XgJ=5FV zw-s5}4Qrm9zo#{!rXYoF{oZ8Tx)1aB9}Wu=3tgJ|<5Kv4-ukbd_Ufzcy4~x4W&iof zey_8wEi7hdmFV|9b?Wo#YV5U6pW2w>skoE-{&9BuFL7rC*3>`Rsa$b<{+;H}rRj#g z&-d;u_yyxp4{JNo|o4lLpATQDu4(`@~z^Q-_mj|6 zjx%SvL(>y>nLNCrwtk+%dfD&k;cFxRZJn-cUjOE8n()~zP5ELLyZz~|SWb=A zD;$z0nRETppLcuPwv31IE0!4ldhYstsjKLe1CQ#>*|R+IVx05OtIWxpn)u^x{x{|M zV%vJxJhZQQr+s5vsWs;*7P*QC?mPbWy?ycO_2JIs=bZD_yG2)<|2%b=C0_gDolA;m z4jxs#xkN#aTgA`c^FZ)<*(2ZHN*}d)YhU7H#3d{&%rbHP!m_VITeg>H79p8&zQxV zP&AD*mdPk-PVDxb4N}>98b?$XaYnB6iFoG}vU$Gcw>kfQAN>CR?L%(;9Vg;bL8Wqx zP)uat#*2C7>mC_hH`)}o@}*~*lE?NrA5O3@%3|V~>=USUbjK;by3_ZgeKj6h?E3jH zp(6gz-dX#PGuo{CFl(}x{xX%_1^=`nd8U6+|MT6yPV?z%AH%P6>;LLcnRwus`jN*E z-~W}Fy=~28NtXTpz8WiiITP^vPH}tT^SjXow#JRz&(}>VSf^rP=MhlJVA{eHb+Z3i zYqS&BgENt0PjWttW^K73*{kxHjFN zIWtp5C+>}HfsnM>8o?b=<=6zu7-Dv>5S*%*SLFTD&A39^IYF7K~=M3-95X)R3oFw9Fbcl_Qxx1*tKxu z+?a->nBCWWzaMsg=h1ZFXOolPXW!(493K$}Va*L^*6=i5*IjG7LPyu3I(+$;6Y5ou zFWk7)cIgn)7k<8zb6R?yw0O*uS;pYGjm7D`>g36-CqjJ#!;w}Y5-2J=jdg9YtPt$Z89$TGWyXf$lJ%^XgoUPMTGCAFYVUG~I z!Iwg-ofcKgu%I|L1qTT~~k2i@zCp z?+z?IJ^jNj^E+M3Pq3~~2-&*CN5fYv}XWO=3tGn;ct`55zvuC1F>E`Xys~GNmYTKSu zZWZf)eCM8ZbGP5`I~#4j;>fDB_#^YpmEU~!Yc{nh-e=7H=EMgDy|@hJ_}yaRdghN# zJT(4sVE$g#QhaTK;@t-1Gf!{-Ju?PuWY- zmrPc@-_b7r%kbLzxOUO(?vHcd|LYO^uy)0obBCty`)6?P`?>84w`j1}|6Eyr?77|l z!X?L!K3rV?S=Hvl+x^FXd@%WU-`W14ece0fj1~E62ko2fmp+!au9Es&t6cGT_O?g% z|6hAo#=>i_R)b-}++qA@#e zw3hF!)vo)t`nf9m{^FsOk(K8<;=H06n%CEKl`9WPzF{3=`Z&%Tu^XKOud0YO@q3L#C z{GTfEdq1D;F8K8+HR=xM3N_YGKa6*8D8B3#w8?5-<-Zvk4Yj}h1+rEsB>Ei@uKxD; z+T7U}?_0K<`&X9}x0~nuJ1eEF>>Otw{8;I>tN!)I|4$4>M5id|8uIPtmpLkHy=`K2 zvE0jEmAI#1@jOqd^Y z*1Kno%$6TJ z_-~o)R##W&Kf2WQq2WXB+&|HpGcL}kQ0|cb_dz@&cz4sCPQ{wP+5C_Dc9$*K`c_Kr z@5lEaX6-ItusmJDy?@TZZ*#Mc*zYTNXtV9kCceik!Ruqz9X}R5ZBjtr!oN}0S=rMU zt=-BUd^vcM`ug?xsz07NI(jZEd77%STtVHO)xB^2RHJ)ep19c5zfifhF1BmQj|!Ww zZyfKG-FA!mVD;^twHMPy$5l@)vi7xoyL;WbrLKr`)pU`GuI~lJ7b)lq|K^)>;MG;r zOA(*$eEz+$_H_V-d>h>e90yDWAy}G+z+$;B}E?9KD zkE3vP=P!>RsWH3n=ACPQF#Xgfk1e)KPKL<4T{TWQH&du4OHJYJgUe5rYyZEK@0Yx3 z5|7rg#k0CZTEbT;tFYSE*tEU7WAg0b#U#1y6DqwP^VgoYl|S=EIr-_C%xgv&*JOB3 zJ0`m=h^bCkx_<4Z6lbq~2Kj@FE;gR~aq{Cme)Xm5^+vk79}mZcJH3sbmiur0{P(xT zV+ua*_u3}i#ZXcGd-lI4O_yJ;Te)74+rgv+Pz99 z{_ipVj|=(tar5oc=l}a5@Q~@|PC*Rd?Us@C~z6-!E`_RoBP6@Bgab`@C;^ zQro-B>uO6Y9!Hlyc=OTwf=%HH)zt5g-Rrxr-z#RHW5&Gy*WJ$*=WoA1ws4n~%FiH9 zSCI!NpU*qKcD6Z(;_Jrb+p z=L!`&A+8x8?s9l02b~bf>U<_GDCgNKXL8xy{P(-H9D4){H7)(mZ)Uu?b;8HOoQIY( z)3DClA?iV$h-KBFSAx-MgSNVyKdK2SU=DGES_Vo8Xcye;_3;8!{uBP5v zXaDW(|Nl1Ju4eJm*KYaWr1v^kO<4Yt?OK6)>;#3`Qs*Q+FGtGe82mL6<+!r+$>e6o zn$I>*ls_>)G)lO3DMsv6c2o8Tbv1QW-@{_pvpzm~w!ky(z2fVGrX0#oq>B^O6z_Gf z?3Dbx`QrZ#Fz`J;`KXyY}3~*;AP6>MJg+nDXE0=dx9Xo}w0!g<135PD_{X*l6(KN48wa zLGFO7{x@0@T5hMG74u{d=71js2nO8SC?P4zf_~o9e_jHd_>55ru_omn{&9iV`r!IfLeeU*klc!xe zUiVuhuKKy(O8ftJA6I|0Dq`fZx~)FHMsEGi;@KRhKkw#y^euY3_mmee9!|cou~yjQ z3&$q;BXhUsivFnhazgWt+rO;)2RLqVEL#^F+H2OdcXDv>iZxmXmv-|eP3`L1RIuvZ zrYp13(^Qh}9Y1}29d_!+a@*g0iN~*@Md#)lyE0APjvc$`a$$d2sp-M{j%Owb ztz4yXXyat@fViNBB~L0gt#aR(de~~`vB&D?lRy8O8q|N^>3ICsMIySnwMKTj`qoop zCVr0CS;Wcg_iG>D*6c8j(y(fG^J!t>3-+xPytgDJW$DrfDR(W`sH~PzTKH6wIrIrr zf$D;HC4!$kgi3+}Beh)hW3=|{S;oYhGIQp-UhSWHvAGVFg$qk!%f5bF-1ES$SmoK1 zXNOYFFIXEWv}kjj@p{;2eoptZ%+AAotGRb7bk0}%{L}czvssnuw&{8s1RaAc!&{>N z>UQMKC>GN_Xug~IYK6hn{p}|AC6r#+FwNm^+rgo8@NLudDW>lCf6n~y!B6hYN;Q|8 zPnXVaw&Cq=29K{>B?0~PYY9=oexV$ z%gTSL4Bq$Sw)(uE|KFE9IJ)iArz~;Xp6{E##_r1L)cKH+b|d1DpZ9CFBU!ee&(!7I z*urHO&or+lNxUrQHVc2`?BnxpbX(`|Wi?yQTRqQSWu+;*ZeQ&Ax5u}=oqaUC`rFI9 zOKi4n_<1<5X-D~;GVZh!mt@uU|Kt1gwB7A^K>Yodv(n*Fc-zJ>tsPetuHlnB;1z`^nBH>3?c%P|NC-J9$m7rY^~e^6Z%GI$`##=zypg6<2+msp{&+p#jr>9Od)X`WjQ> zU#s%wr`h%)+zVr40D2O zN_Owr!DMnSd3xqSx&GjmIa9l({;uN=niM(V*^WxnB0t|=q1k7?d`bIfZPl;++O%ycKd{*^N-y$p6F|&Rt5Lobyv)5QFp!OJOF9vWYEKylQF33LZKcbG|D2 z!q0zt#_FY4uUgbTR4Oty=5$R-`o8b*jSY3Sk!rl|{qqH%9==;Fvpiz=F0S5`xo@{@ z=;ksm_;DgqFiS0Xt+MNuw5vfYbw$|ZNcs_YToVsU%p zk}Anro(CS^kxNNmI?+DPeMN(SQ@~+|dT}rB?h~?~ySb0%n6LD-6Rb$nIpyO$DI#Xl zd2O-jteuIbyMq-aza^=iN@-Y?cJ1-%k{FZb{FW=1TmD}ZEMK|s`eCuTmm3Q6+JC(& zJo)}cZ<6A4&5J1~-#!ybH?4}B`dn(6zMk&xm{YkCUp`KJb;(hEL+_Vn+U%=asQ+?3XhHc#IDkV`>RQ**)#-@4hyg{KGZUE+1DS-V>> z`sQ+r4^!e-a5XesUcSylIxDV@txv|%J#3Z0OqPCr8Jk{FZ|#Xw9vz-%>%O7ts8JA4 z;f=k&6|Sv`)tp<~&OiS^RnrZ-jm;B?rG9Q^gC~X!vD{%9BY#51kh9zP{EKYM-RUpeB{bx*^YZ zYY*FF){v+<&CW|0!X{oQF2A*K@$whNtCt9Nu&3%Ji!WHnXy?Rma|uJAjBVr9?C{A< zGhEbl?{u9i+7xkEC7{s5?~|90%1j;G@28(XP3sOQWIHG>uirG$L2uft!tE`tzUe`s z`GS7T*-n!qin{e?|DPPsA~^FU{g)f= zgeV`%>-OB9`EXy2u1>i_fbtRd%?p zYw>yQ-8KI%O|psE;bFJ>dh?-4Izsa{v#d6rICXa0*-C~ z_a)i={Dh_2)2kYpfA>#fxGLb|r@~s$A#ga#g44@Ex%z?q`HL96#K*rxCFG=?v!iEgEaMJecPYu!p)ODCo19J8*41I2%$FMvt8Z-W zJATGmT+bxw?=97g*Dt0vq(yr6Y0MNooz220Z&^4^d$MKsmFwmju`_&obw6cgX1TdnTkrH0 zR(i6pLRxaR%aSEK9xi>q_eqwYUynymvvhlolf+{~=J|?_N&zOR z8Ed9*I(mdbWmVD)(QAsIdS{=QBpI=5Pm4l6Hxpwo%N~(%y|~8XFI6>W_g+@_S60^L zzWH-yistKpN%1ZlZnOud>o3@}g(=gsh3A{>)K#Wo3jTJ*47WXBgFjI zS=YpG4td0=?iZ($x?zskIT@+f(HpaTd1t-cGxMCzdISD;KH0;Yrk;MFbkL&Yfy%Yq zsJ@$$6PPj%WI4(EEIzt)$$xvYVQ6Ek3J46-x!YgEdy?g*w=p+p^Y35OBeoLz>!&1{i{X5rD>sIwzQgI z&zto=m(~8x`*DSN{j+ZmW-ns!>OTD_ChvPS7dO|$bGLgMp8V&$yx{gX-b*uzKL!b3yRN5b zVxZ`3<8_+5VC~*^u@?57Px|IqRfD%jeT!y^g$BI(YMh}cD)z*q z&gwj|J2O^>u3TfVCS!Nrx2PLu)~6Np z*rhN2{-K+@E#ku6CyPJ-{BXuP^H$tW9j^gommpyZAQ+^e8_0FD`$F7xE zefjL3Q>53!Cob@BMfut8JKE)~%?D&w*9GIEhxdyYlvX4;d4z1{Y(09h zE<`-}#2Sk&=O*ii-wxQF^z~tW&FjYST-OI@0~u1UDn_Z)&zd^-wVt}U18eiMgZ2OJ z@hC{nlCnSgbpLeDU+eGhnDXE~&$^g>O}(?jyc?FST`Qe!rgM1fx;mdeza&pz&Rgrg zPCB2d%ss2Sc)HXHr(XdMOx16WxQd9RalW^kz9COx#<`1s?%RAbi7Wp7c2nIqIg7UF z?dvCp+&Fsr>z8>_Jv`?Z?A*!fJw3F8>47AR&z-`jS&KigsV%SAnEu|d>HX;imzk_f zR`AU>Upqx_6ZdodM)=~fNS)=%)#hV+fRbHKAG(UPwTKi3h&?Sja=S~RMb!w{#$wyV# zcdU_B4(d$q{qQKq-KtnLZlA-8(|R`SW=(HnuAjGIT;?jqdTPl+rw@+T&Hdgn6)RZy zOiSGN-bdKZ!idj3hDoUAxD)R+8oCr+Gs;_#q!@BOqYwUp4B zkKOkUGnGI3;hJ-MTiCPbb1mxFZg0<1*q_I@{Cv!zYj3kJIx=0mc~4h$caMPD$)@lS zF|NsLPd^horOo$X=`yuW`MM7UvRPSLsjkr~t#gQfzrf&LSm^WzPdbB7oIUBx_4f0RPUDE3d!+cp`E@go8wH8w z2;THRbJ}0L`|O*ea{aPLU4JG8&ivlA`^OQ!i@Fm!jl|Y3kaT!tkYUgwv5;>jlm5OP ziCdQ{&2cwB!!U>C^NaMvLy5bzK)zA-Bqo@xoM5QTl({Jbsp@J3ssc(nLXpKWlUar zt;#Efhwqj1810$g{jw>4r_;s7z4XB8cN6Uko7HzgH zvR&?ZA)Q0fVE1Hat_wz&C1;8*?1?#jX;P8m?x*ReJ$wztBE7u%xU%Gs0Sh4Pb(zOiB-1ug8JA3T) zU_A4K*`nkFPu}f~jGI|5f43fp}H&rhc7xkZHuy?w8+u)DNia)I6c*9LhvxB0y~ z{awiG#-`pr=MNj!y|XdPi|D_&(eWg6cxZS+S`|-R{-z@=L6aVzboWuwe&tjd$rvfq ze;}prSMi4K;K-bhqRZ!WWvnh;HJh<`YPQ(IZJ(Y72)>>XE%Gj;`;X4GIkok2ek(WU zpW6`Ie%$lgo!rS+X6>=DS$I+}lEF@X`H$yXd(${~iUpgB3+idF6`grb=Iws>y=#Im zD}R*=USnlQ?|3k<&RIYIM>Y3&YG|mSDwWc$2eN{mHlV_{ci8~d*Pur z50+^#+&k5!trZj;T&@?rF+^ed3s+?+wUhf_DN1oMZZNQMwfmjBJx@hD_wZ%^w@2@m z=Q?|se|VC7{_(us=pzOneYnj&9r)|*4Ocw5-2*e+Z(Y%z5Lx=;5$ zoqBYIb#0(T+2>D}HrBsqTobuhjPv71i^45@udiL_a#^!JKfu+3&r&st<>rTJX&-Pm_+`JMH!xFf`5hNZwWK@JHc z#f)R`m#?o|sQG-;>zg|xS9*7K7b}a*5f$&d-kvv^eQ#b`&YwHi_x(I@_5SN+cb2?e zrr9uOj#9i=)+_62y6Z2lEqbtl$-rB~)$YtchA;*lf%7({4K3BOjydM@s{T~oDg3Ql zaIEsfkL2?Yzkbg-EOYnD^7%J=tKaR6O=ByP|GjPQRtX6SH}7KcYghCRemKx#@G?Yq ztpJmcp7h!C=MQ{%&|q-3N_ftbYIV-z`%lXXIq~?#7f#U7-`>EYuJF<#zh)CxLg8yI z_t|G#(|k8RePJwqJYvFK16?PTrEE)Ce9~qX@OLwA4ru*T^fA<#2Bjtm4OuKX-Q3&1E=#Ez4!z?IxxlO-6Nl z74(mMF!_H&KQ#Bqy!Az_F-t^t2DDFA;-8|arl`MOWBU4;kuyDfo>=s_fBl=Sw#rC} zIbiK{DP^%qkvwOn*_b~Uuc~^-`tY8>^2@5<7w?Z>+E>{kQ|@)n&sU*Qgn`|?H8HA* zF{tOs0@sb7yX${n-~Z#&-}`k}k1*%WV)FR7?3Ph+(Y@H%;J2OK-(AE6b>`2{?|W+g z@zJAWBC^$Gw*6mUUst&I{K(}Nwry{3G*zq@?*E%+p0~evcF4K6bmbEJjrEZ^jX8XiD+vS1<+cg~f%9Pg$o2`Ch`si5vc3q1+>5T{Xz23GW zK0f@7=(iVVx6iDrh8=57PSn$kFkq)3X1ccPuMr_oT({Tl{ar!$ETnB z739`e2)>?pFu%<*C^AwzEv@v?gMW`#MDB87%Y1jYSY+$#Fi+;wjepxWKApBTzWL}A`M)L7Wm2KV2uNjn1i748gmC+fjY5H$o z;%a*zY5%v)~-X$wN+t{lsc6{E~S{6keogWX=w+ZYCtFLV2 zKU!y3CI732)ga&hV*PCYPh2tUC#=a|zrQbI=|bHd@++Gzn3%H8=yZMNaida1hSRFt z_0xRyV{V*}&U4itzVoK#%%V9nW=syusM+7%#`fa#<|lFII+Avly_H&cfzu+EFLB$f znWp>GU7efG$4)Ps{nh61^RN}dCO>Y~et*C7`@L%M{p;%&y!~E$Delp?dFAy#K3>1~ zdDeBk*f7;;I+qq6mDXkwv-D;^+w^kZzV8?MHzq$<3kef_wDJDCW6REFPnb8)FJPaq z#@g6(EIz*eT}m5He+b;xac5n&dFw3Z)U22Y3qNMolcisKosKZsEjp>C)TmV%l6a=C zV1dsU@sO&Mv(%IyFU~k#cK6YWev$1f((UXQt*u+{wIJ7!yXNA~2B|d_yRA-7|8ZsA z{qKi<@BgDr<&>Bww|)C2CiF&Aal<1g#kggfCs$_VymBZ%-w?29`qZbFZ%M1o zudzB^Ce_H}01vo>z$J}qg>9@bz**+t;q~omwjfeeVL`?9U3Y+X_9S< zVrj^v_s=>vcTXth@_ThGv3;&`a$D>l6V~4{OqWG_7w28PID1{|r~QdncStYe&-eT6 zXkn4=VQj$Kn-Ck?>A8HCZ|SO&+F6Gt zyi)H!vtai7WzmOnBk#W8sQvLfe95Ndi7s1eT(#}F6fiREdcAPT>laZ| z0-_gkOC;8cXn$C^!RkTjfqg&c#0wrOx^31!eKMnb%$p;77+KCXr+mB}C9S$5Yl0I8 z>#~=Zi!-v{J0ur(_ozRf7PmXr)bZ>YpVMcW-@VK8@$>hrQB+p;ox;dtnzd*7_IQaF zS-y;n*HzL=J|DhR^R{e?1A^bh31L7 zS8_b4egE%9bXNBDKX0yCm%TW1i|ex0DJFwpUn`}T>k3jNyB_zR*Ymj`u=hhxM)e9N zGlR9cJ0_?8OPXZvp3`#HX4{XOHp+gFV>XF>+o?PKXw#)vt6B9I>jhmF=(74h<7`0f z)6d&~icb8jJ6AL%W`hLVMta7_;vh*t4~9HUyPZ!^t6gd`_j^I1KV^3Q(ew8ybrguKiIO;;oeT}=@+m2PqWbu zcbi%G@Zygf2A7O3rJhSw#M&MXU%F`c(CwC&B-rv{I=2iXQs_f z-nOz<*?8OTuI}#t8Jk)1wU|zvKEa>z{AtaOUAr!c@g6^{5hgZm>VH>@s=P>f)Ai?h z?nGpo9)6{?B`)ys?n6fnwHS^+l(p^`P+t3bl7{v2%OO+l`d+g+xcJpAONHYznfl&X zt(miv<$+SphDmapg0eblS}SG4Hk>)d8@-XYcAkNr2tUj|9rap=F%gpvR_3OPno~gYVrD)D znP1+#g}c{cvBk2NkLK=p`M$Jt`iIB!Z8{fy;tAsydU5)!zuJj+3%<`X{oit}VwX|0 zn&0EIXMY)*S+y>_nAzihR)}dvv%aR_zXv*xIA5iwE>o~JmQ7u{)QRWR6J1Wuk6Zkw zTW+#bDdzq0Yo|k}=F^>~aZ8W*p4V()+J5$7VRh~9{}F$g%tIMXOycEkZp!?9Tzj?l zU_IPvKqPj39`Iq0H9guc3n63DBg-^gs!GC4G4|YxP+AzU5 zXZiHwIdKo`id7%*t^9oLtH&1GZF{bAr5=6sb%x386RY!n{k@o}Ys_J$f7P^p_qjvo zs^fb$=q4;&{N3>X@1xshe7=~Z{WY#@Y5l_28^5h|j}8Cg{a5c(nCH%k4cuF|&rD0! zK9@gfC!<>Hj{El7d+Kdw-A?o4N@AP$__$wER+iVTt<_b#A1r$QMrEm;xwZSdMa?xe z@@4khxh-w@&aTaP9^*G(VBfiOeaR(rSZcI7{vAwInV|ao^1NAd6t^t!aGo@2($g6> z?ia-0AKa80>fuvx`p;39`QdF3x0!5DDk=(UTdsEDzJ=(C4G_%Uv_0-IgS_ zY~Qe-eTI&4mvWrO65r{L3cJ$!3eD0Fzf=pkzSYAorX^_mqLbM6rVnvB-__MC<+Y+IwpuEH9$ujR(p{W@rK_})EZN4pXesNk|O;(lI+PBw_ z+Mvva}C(|Rnn*OrBhUuTHVj?;}>q2G%Q`s z#rg84r^Doht!XJQIL<7bZ(Ca%qw)LIMld-R4Ds!4-^WIR?(NLmuCD+Y~lP0ykduQkAzii^|#AGW!$KAzy zE?7VNvu*b#ZtnjNj9K%vm>%R_Zj(KITKkmw&KJj8eB8uV7bH(yuw~~(rI~Xlo-@(E z96D2XMPbs>xoI<3#|F9@q7vI%BIOnftr%+Z@|uXs_& z%L~jd52~xG1i4mJOt{eHJbhm6$`d`^?#|B2no|`P+UTb(Yuvaol84t{pk%%p>x8a7 zcWVB;N#8#)?7hW$Z?_)9n?72cg^7iFT-?QhadAx_Cni?fb#{7gTDL<_@tm-Jwnk^m zbkC@?6QZ7;o<~jQYJXqPBm5^lzCNc$=J4XjEfy!QtCtu$t~>nVhRU+^G}Rq1z8yKq zvE3zq(angXrzSp@P@I1_FaBTp_Iv*(zqk4ILVk+dpJmz&rdzi!nKpIG9#uWNdp&#H z{}#%b^fY#|u>P*DPW@IhXM+8#BmH3wesNl>);*{$c^AWJzlcR8DnU$4iu;%HtqTJX}7Jd=-mblf;UPxWER4UwY99Cgvs{#S!yD~dW^cQ; zW95ZEMCc!>(S^?}SvxydPSQ$IK9qW`M)u4c8zU>V&;^n+XEwNM-+^V9KDp67dZo-%)}74BvK`{b|f+qWcseI@GQ z7gTq1&o_w~`+GQcr`}zAAZQ2o#h3$8IZ0Y(qO7Z-^TGF%)p}Pctv!@nNyEu?|SYw15nkP*|;R{!qrQWWs{dt{?aB2s|~bJ3FG;O4 z+1svL^Lwk`r>B!AxV#Qp+J7}jT2@+}^|GGGJDV&!d;Rc*Awg+c-HFqWEq-^9^T_1x z36m#tE;C5IRUX@Q>RB3({k{275uYwk|JhOh{_QgDhW)KFH*n&nPu zoXgg=hiq=q*)*XiZHvF|$xhSQRq(RwOr?jXw{x7|HqPf$g&sXyw|a@fosWeg0s#JYSYan;!f+mKMn1^Xnj^`#HT2aXV}GEZ!VkQ|ZR~ z=9rJazk;@IY*MhJ)%@h+{tNo=Fg~k#P*gJeoU6whro!Y2?0n@iZ0v5WH&0HNa6i?& z&VLF+@S5{m{m=f4pBx-g`0{%cgMRVumwFC=Dx(wbTIa3x_4}&J`Jur7^Y=4~=coIA zkAG|w)tg_CA@;A6(TC3<)-1EaR)bMmZA;1yebZmlj_+fb)2}&ytJTLD8qIu%Rw_Mv z_dFx-i}_pEk< zTa0_aB&l_hlRic0&3pL%XWYq;o)>$_^6W)|Jq8I_-qF=5T(@LwMz zo0^T@T-GmaE_wOdL(D8WQ9bEX-#*7JhN)F^vQBS%mz+~=+RyrYOM<}CrL8y0A4qKa zRK(Jm@lC;|(C($-#2l93xtFj1YgAnMAvumQEMN`862tCwmdduiULD8XmR-I3z61hp4&KA%(X)-uv_d>`E8Tm{c3IO>|btPd^$tc zHKUBjSoko<8Q+8UwtfL8wL2Q}eZ9IqZBZQ!!F;$rA)goe0=79 zXYu*hyNYLSk2DljedG0@@?+NncF`@*Us*o;+rO@M!c3OEwJfVAFVzZC*tgKiyz-y? z?>}`j?>sr=P;b98vy-XV_M_aFuira^9-cb$=8jEcUQXyt!I`yx8z(9Xajh3<|5P_+ z!sjK+8Vr6JtTx)r@mbsB_zcCTwx))@dag|-K{s=<&g^h5U$lBN`(N9=LHqS5*u0vj za4Ld>>7)OIOP$Vh%sG$y$2r6muAB0{NPWdYSJx7`nzcP%KdPGUygD5`CB^H?8V#m* zFB7)6-af(J?zV(`!uOL0ecW8{R3G}Paz^Y(hpK>q%8%n`T`x~=$vd9DWUbBA7@<6= zB-c}!Ugy$0D|bY!OPKhs=y>hl+4pz7yzy+P6;4l@IkVF)O5ja*5kDjU^^jT)Db1-B3pJ-}yscT?dqd(tX|KlTDb7#a zH_vjsoD`g`Wbo(gp}f`$3nJGwJLEerDB1FR?HuK)dfYSj&whVQVp%|x^2S!n6Dmwo zt2pniU$?FybA!&;Lw|)9si?azO*s1cvuCF9{`ulXcW-X~vRmaz%5#p@0?O*|LQ-Cz zSRyt3r2O+mn$L`$JT@p?DHwES5ARps8B3nem^D$Y=WLT%)2aY#kx!FL-#D2$K5ntl z=bXdEQ%=f=2y?}aWt0i=aV;l2JtQ)B2piIB>Q)iK5x{C z{8ApK_UfYRu75ugUmRQW!KO-R(}%0S}udh>i~p=VCT$E+`RdDZ_^TJ*JR+w4Au zHE-SRe_g!N|L^U>hx7mcdH&Gk__14|sm+J?=F85MIBw!z{I@Q3sYiC0PNdf5BuhSp zE7#?wd(Dmzj`Ly7Z#ms$+Uc;_Y~CCx;fSMAGntJtGfyV1ys`bM$GXdJx!P~)BnAb3 zXjPYJt?y&yeCXR>wLi6&m-Cm7T*#J1pTwLF*pxT!=bd?9!r;)K&#(4~e&pca#=#QW zpp$Ya^;>x4P6J1daPy*-TF?yu7f36}>xWD1HO2ot0TW*K^ z=klNWs7X$3QX-pT->vpDod=njm6M)IZv0dnuIX=jeByiW2?FQuoKaC^b6#du_*BzA zzdoTYZga{FA;SyiE?$a__wtRWZ_}vM%f0<0y#D7(^?g6ro3D?5z`u+^?3P(>%*4d< zTld&~L%)7>;=iy+ZnjGNUD@T&*7WvFK0j5@XPwg-#m7q)YrQoQo$-k8;Dkt_Ggl)| zp7bmUe*BW{x6d(|c7ZyBH(O^5cORD9C>AQxBJR(8Y>CL(6-R2GB(R=+wp;Y#Z!YGB z7aIHJW~Q9~w?kD_)Yr?MOc_D%l#msu&}Zre0({*`mxxV-h726bQuf6?rqImA(H7wzrY^Ful z$CrrCc+9D|KTBu+Ov&jV%U))7o={l0|5_FA;=_-dw%jS?oBHyS)1|7M4c!jMU&%{2 z1Z7PUvGCk!J$>Hohl^|V|DHH*_iuLn-|O{rYh4d*JMqmulp)%DUD=MucjUPx9esnW z*v?3PX#4TX`0}ac{>xmC^@TvF7&c zKW^kKj#{7i>-fiqYtr1qm)A_2$hkW??6k>z=IDR(=E+G~JW)39o!Z8tc-F>#w|0-- zjQ+rP;+zi;B-qcmFgg2kWgU~h(xb3=J?>{w41IwXo;yOg`b5|H?koB#&n~)JYx={9 z?sBeAH)Xx>yP7e@f$gyOq0<>w7mBFDx$Jd@S(p%RgIA zKkVF`?H4jNJmGQMRiO=nH_~s$8c#iX$iUD_FFsXeXWGVBQbFS9_*?HXOS+~8J3629 zcUQk9=J`}z0mhmYJ;ceJ_Gon85@?c^tEu9;$U>g7%PPwrd%NRnmx z#!0Rdw;0S3vUvUawb1HQnM!X}A8zlR2J= zuBU51$3z_dJ!uWsW~GUJkFxfzyC?T)qpgOn=Cbn{L0Z{Y8Lya|C1#|!ta@|G`|2BJ zQ^gws5@)ZxDsxiX>ALfY_H7jnb+g%1)Q)#bocx&aed9*YO?QejGFG@}b@jiy%2Uy0 z8C+g??8JiE#~(iu_Kf_H{&mG6Zca9?{Kb81*2KKITP||Fs%>M@T_IC;CEe~RE8-s+ zD>hrIduX0#O?@;$E$`VHjgCYo2g{o?6O#`bv+bPOaeAikzv^1vf0v;lP3r5DEjy)GbJ@;=8Gc> z=1YJ4Gq2gHaH<F1Ltj$HY%V2AXiNhL+$3!R^_8`wKURSCV-_j|-pRLhb-JNlMt+CdxU zGafoqTc1^!th3lMIs5SZ=kFZt_A$7XgGyY$W5zS&xOM^0$O9^8ARwdLyZwyk%2_V!)( zzFnN#%QxkzNOEO)o7}|Ne~K%AEYs7FP0f9~sC#{}&=2-U5e=?Byc2E9-f%?s@@f8d zaCAwI-1YXF>6V(GMz7vxFF3c(E$mM~QHH@mgVQXwKc7rCV&AxPXJ?kyE7iER+no8# zo!i~zWA!WhB4cAGl@u>waO3l`7ty9yUwZf;F^8BtvSE;)t+DZ`pkM+35f}DJc&CGnm&HNH}|+-*U`y` zwsmXuRESJF#Nlu==l0I#UAuO(Y-P{qWr~Vi$dT|TsV~G-dFH8&Mv~KC-@ANSm)EH- zmUZJvcXodHV{Gd5KZtslOYalqIiI-0^o}d&Y|V z1;WRVz1U{`e)(tp3iYj9uLRZ@DGNOPrY9C8Y3p}sF30;68;PW&!jq3=l>6`AGku|F z`lL6i3=SdT=bvA`r}2|vj&MrM1`U~Wd3U!pKmObCB(>`2*Q=qaUG0}bJn!y#IDL*o zzW@G~(5z20r1p7LK7Y8;<(DnDm`=z4eJO83*D~ns`7l{@?%T#v#`*b2Rj0=s5s%4D zD!mn){Zqa8)J-e%2WgjF|2SS+x$)@|^WcSI3tA&o*{>S#Jk`?LRdhONZF*ati>WKed@{Ik$%%`85Vu*e=ER!>!M)7^>v+hz55>iT@^F^q-Dw7t@jrd zpRbh;-CTOy!uWw$)$ZM)FV7$RvQS+mUm?%9-Kp#539;9Fx*uNbDrHh*JX$K6RQj`I z{S$!+zV?NWBd|SC1{cyhJ6^_D$!5q6CRk#q8g_`Pd3# zraTR?-sUdC9#LHO_MWoX`u+RoKmMx4DtF0?U4n5!+P6ZEfU|{mXBcSmfjW-aQf4Q#%A}Uuav&Mdy^yTt>feu_fh8Bo#OpZyrXV~ zPTDcUWGmO6KOesQVVr;E9^*;T!w=qZ&OYLuk(0I1`nru1?^)R^m)Thssd5SZ>78NG z@}21f`&7{urs{8R(_hCq$L^KAwL7qyxjMDSRzc(Mty@*6Ha4wGbnWC~I5t^(S>lt^O9_fZt4q zm>Co&^DgHPW=`?Be1*&D=+6%a4RYB{5;dl;WLYx3>9L`dT-T@UO-|-|#ws#Lqmn;7 z+x76*d!e=^MN>TP#@aSzA6Ub9eKA9toTuHK;Ns%d9PDw^ji+Ywys>=b-NUA@o!q^a z-G4>m{B0WZr215EM@O~3XZZVBa@#zQc~utYSj^-mHyGRqntF`as_c=)e_Q3ebpP^x z4cF^}P1Srw+yZG_qS49Shjb>)lRtG{R!&m%Df`jK90xp9B~=aCUPrwYXPDT`A|Ac1 z#7I}pw_$3zX>|2`wQxrZBQrb2lU51F3o`DMc_gC-T(>f)(P$rF>(WLh}mc`oy-!itSI=G)EJ^V}txarnT>^&Rbt z{fjjUUVK+fUZ2IU{Mu;t zA{p!DL7st1S53d>D4q`0Z_rz>cJYx^Ur=bN?#~-ui41K!uB>qTu(|1RveRl-n>`2G z7xoBj`cUr5bN5b!`rOjGuni9jTAVH#goaG>9{6#P&gqN3n0CiR7Bu93_%VugEnO z9iDfbfW<;peB=?m_MulwY&t-VjqR!@|_#%xNrbY)Z2o{cLz*L%8sTNv&i z)pi>{{hFQUwI}9h)m7~Vd&}2f_m!yqy}qZCiCc^(D01g|hK)xj z>1YNe=cuymKewHkVbL6)0>jiF%TIshvsh)mfGvI&)7h4#-GOFvCtSM{!xkl#J7-l$ zEARIo!Lwf;{9W(*R`#sWL@XOmYoi(5<<=;HP4UfXU^PpU>(n);*uI zSWIQrs@E%)Eo{{F3lj01$Di{f_x3jLo<6x^#fb$vM`KPqwYnsRyIYr*o(poet~5?a zULbBO!*x=}DME(llgW=5hRnGfewU88c${NYP~eys)X~=Vdy}ZVl$dMiIXU)ohNoxC zTvtEa)Vk-32Djz8$TfnWxODzFys!-GtJ-Ci`aw(R>xPKV3MU8G4;&YMFx%Pm&$D4+ zx$mOlb24Yvt3bt;6GkaW6eH{}Pe_WzqFmd_8 z&o;Bzcspnk6+mR4l63P-qP+ z%ig_fBa`xXoCx5#_@Tw*w##A1Rq2kU#Tq{hO-!`j_x4z{ZQAv4;@SR*k@62GFzV%{ zy7pE`ud+(&oSxiyNNVyK`wJy;Gat;J9%Y+winq7n!L=aEN97$2?hAh!OkqC7ysk7l zd-AN^2j1cS?l=mu<3p)4~s}X|MaM9ks1yXA94vmZc3mUG@$)O5a*)_6zQN*CuVg zN9O0Jy>rC>D_-NT`_TM?-Tp)Q?!^}?#AnrPIJh8IcDu~-o1%ei%rO$b49_1buK8h+ zA7QF?>)K_D#6Y?D{jGIB9^ZbMn{VCzYSr`&O$paePfmIrclgwSW!L(wwuJ>sNy<;v zdHaX8w&eRO_7gF;l#QP~5IbBg@S27DoxX7Q;$vmflQ`9EJC9B9bf}BkR$`cc$xZX| z&x*rKE&e&{%xAb-GC64`qvx@i>2vf9jbpwYRz9w}k9|U#*zq0*M=iyzD|hajXFE-# zde>GH$vFv$xw;Wn8XWo-FKifBu01^0<(uT`)cBSKO5FD^-BDT~!ohN*tf(wbXWc2@ zlJ4q$qc9z#lVNse_2*7`sGYTB_M*b$-&e0&v8eN;fa_10+YyCRK0a4|J#V|nGKO~s zH%dGw%+u;&_-;3ayCu)Cx=iDt;^)3s9S8TB+UbjQefl{gYUez$L7vBf2x)<%UjQzmk(Nnh&Jrm1Rq`k2HHuWu_HZeI12 z|NA5UvVHBts;H`4N-OOSOp2E2bG^CS`DVZxgM_1(0v6qqKFw3mJog%W6ZP7$N z>jggw`#xxdDoej))1Az--*@ZO(vpAH_Z&^1%Csd!^t^rXbEcP?%+>iX%w<2HPIm9J zxqI#U_b2~D_QidbW4QLx`~0lQ=bzudbN6!Uf_5prsliOgzh<#X?l^m4pLyMLcA?8= zo4!g&%1-+vqQjpQH!b|u_I&fLrrQH!LnY77yQ}20u5GDAwv0Z5wzH1H*`m#kN1?xnAr`q!e{({KD>Lzw{(wcqg^Y)+DXqUCK6OYK@uuCds{JG&l!-B=L{$E?M``!nw z3Wk*_UP65w$pZH}ax&&iaUS~k(KBq@wifmef3C1hYe@L`(dUWZgdZ$2k<-qt)Tj#U zFAI|4U3|_{(rEHIjvN{9PoAxoU6KdCDF>`rr@6TCpyRJs`|r4P`$ubhXPhp7(rQB6 zuDet9@|P^W>v&jp|FY*k4@(&4IL&C+a}3oiWHD)-*XUuPb!z`y(VFt_I7Uc*{cZKHc_n_m?)UAN|2uPhxmh~mF+6M;wI{{l&b@TA+^JC&+13+Mr$uBszM3gnCiwVD zNc`cvLRRf>dsGhVMEBY_mn&7gZn)^)EM&Gy`Q85Zx-XCCf9RdBx-PG}T}t0#p_2GvFn{a-?=c+^V374ho5_xYHm$9@*R>hP zc6;lIZ$ll)6c%P#ym$oNp4AxhwfsHFC@bA}~}@82;^xp~p^ zxRd1UsGp0o_I+HNZ~wu*k;|W(b;E}0xEl;6Gnk*Wa5vvY=M ztK;#$-b*hsdUU_Wc&R_$Qvbg0RI=Ti=|{ePd2vHzX=I_}Plp~Z?)F>f4(zd
w& zOYv&i+gqo@7P@(r^73vK@=|!e+~7s!OjnLBoeyWPa_9>|D^$#4 z(sE>SWLpy{-7Y<2+L9MLL?*Bw+?I6sq_^pz^c8WeIsZ;}ZZKguxO&2))sLs1?d7ps zH(Bd*jiUC?mMLE#yU=##>;}P z?{0qYJhf(BGV{Udf^1q_|9eE2Px_>}&wLNh(iK-iR;!trWLP=vHeAK1v3=UN#Zw+d zZRDCG8qC)le$hG5`&ZJmC5u1qy%yW!)Ri+cUv#KF5(-|VQZgg<#k@R@CVwsNrwh8$%r~!F z*p!uZI`i=4-I))WOqcPToFD%`O_rDE%cgV#uf4IpGMky$--imPq>84CE7(X%Ns5_^ zajtmxPR{n+?bX%4b6+OkuYa)No=oqi$`3J#=b!TSy!o%O-@QJ5{-bTo6W#UnPbmv= zafSZU`6eS07WeT(s|BC=P3@Uy*K0P-4~gNLQ)e?(P=8@(tBB3lB<~3u9x?Z9bNIp7 z&d{O1Z~CF_7N@vAA6x5wXkv1@X;if7rUh#_&ogbwEiDZ_WqnysE9U*hiwpcJq*fJQ zSlza6Ma$0q$3FraGtHe&N_IW=XSukMb>)p~*HjGc=hRIR+gr6}`hNNLR{Tj|#ictbT^d;hRanz4)J zRiV1b?nTg89M`S9V#Q+(7_ zY>s~y;9*(E9F=)9)os0HT&9@sk7#JnvnKC(XKzjMm@VR;rn=bS<^~)PQlF(=MzRc|)!g49>n(R7bopcQmp$SlG>N}bver7!Qv3ruJ z{GJ`(BJavPy6W+L!K$a)*W+yzgPzZM@SCA&5=Xnw-rB#HoNB*Cp8jDS5>)Ly+hOZ% zYbn)(+yyiI1Ep7AD{&V*D5WlY>eA$OUsr#%xuzM;Juy(DbocM*XL?aD#}i@rafZ^I+4Jrx zu}nJqb?TLXXie#mNjYsr7t7ySxU}=lOEBl{6~8-4z~$yK?WTiW3pVv_%fIdIEylNj zsbI-;xySP_9A%vzJ)T$Vr zwzqt#Qa`_x|u!@mXh>xH(2_Cp77GtQT@&(wZ8Y+7d6|x+k2I7zSz+B{ho($I@6` zqWx1>mSE8&HOUTxlPyfZm)uMesQmV ze(=UpuNCWD51tY4>e6aX$y5qIs<@D&WP^C%q;pFzzY%6@%lq-pw|`&A&RJ$$56&1* zf0}!`V*Yi*SK|6{C-hQXA0C>jcjS7TzJqnyyX6Y^-z+;O^)kAD^Mpq`?c}BO9()VE zxNk4}iiI1!qykkgK2ux35q8T5^TT~@nwoC?zEgauUO%=>M<%0VqQu=(-lfV?+?!joCR|JW=%gAr{kesO zDyLOMrON45TG}ed+8=o?yTo**alvAla9z3Hd#5B`9h`4&WTL~xR{QQn$K(x;Q8B)s ze(+{`wn_JV51pI6Zb3EcnwG5Q`?6mazJAnNA#vaTnX!`k!^?-0dG>D9y?JNby0^Qh z%4}~vt@&p;i`?2%Ssb1IQyQ#wj%k~uxM-iNl9jb62q+T1n9*@)V@Hksln2vvW1YM! z;?KT(om{@J)Ap#=M>igEZ-*t$tmfelxOOl9aM`xY%VDi}(qyf7FL@WSg1GE3_2#Y)(i{(sXF?eKr5C?)uu6SdSw!uF5ojFD(yf{_;k`uyz6g+B)^W$v97ej@M0vR{sQ*^#J9hexOE`z^iF zU&QKqzB|v9?DDab)qR1)j@>@j^!OWocY2*%$rn-@vFpjoI<5eX^=c}MFLF2ad$DPp zo$#YaRp^akTf6h)hx+UGBtO03J#}^FVun6B+pPJ8&u)JH>9m(q!!#m|@xR29(~7Ii zx}M00P0Bl;b8FFyBT}=ECZ%m&(0yuUj>Y{uhu!w=-O$HpQ~LmjJ% z4;FK`U0M%og`X&KJLJ|j=e^CHbj$A5k!@>D_Hkd%T@k+FhFjn4yOr$?OOFW~&f@S3 zxV|Rx(V@kbCmw5r$k_B8cJDuNjPV;|@vGL5!>`pY?ODVi;B9VZ!r8htpyMTPaS_=$i7)?wHB|(rT7P;*AzCsyH(mAdfdNX?qOQ@0m_64kaF8Yp{ zMQ`SwDJw2#2Div|@mVhH?3`dM$tCNXZj|jLd{TY`5^J1UwBg0JzHDxt$A4;4Rt2Vh(0*ipbou$bDjlh1 z&yGbMY*ge4ShqrPcFKz*6Rymgc-Udn+0y!lbHr#!D>#a7wOFN&)WEFEi zo9hv{XgXJ$hEDYM?A7(V54*YWE~uLQ{I#I(#hv2t6Q8#Y? znryDKzaLs$c78tT@rmUX!V|nRUva$2h5r|f7d+w>Vv^27$s7C1WWuI zx1_Dwu=}$_%q5}k>2~YWv=^1|Y*8vQ(&USN{87YJi8JhjVsXhI7aa*6ISJ|cd(ulx z{=7{--aP-_F4OX}&+Wedvwpwp_qVg(?`+okvisDP?sTm<*VkSAafbTYlK$sjzs}wF zC0{QseCMpMjj!D@>*|hAnW2&W`(<|gZ?@ePn=?)>`k9ls`iPX{hCg*v9d4bS{d{Ao z|HYf>>la-1lb&++c?4VNChL5``waKCnE$Vl-TQiO{&M5#UoU28`2DZ>di~|u_3@6n zy;Du{b0e_lO}B7cUmv{BtiT zqbW)8=+-^i=jA*N^k&%4pEY}y$nH&xW3s+@Y3N_`oum24$9eaGO;2rItsh=ATy;F4 zUU+rh?N&}7J?Zt2ckOivnIdgoq<%?Avz=pFYPOI_w4L-RCo5LQne%wOCyC0=t^2m8 z;gYjNtB#G=!j#uGjSmZR9Xy+QJ(63xncj$;bFw#ErqM8&ef@-cv2EMleCP|=KL59@ zcl+{PGeoo+4#}LAdMZ*RxlSnH-QF|iCR3~XgA6~g);zg+RsP)5vxi@X{L(Z_kiLFPT-j@CD z!?L|UpKlM=nX|xny8gnQ#nxZk4)&(xp8n5w)ac9P`FGrw>s$6dy*>dN?=Z(5qSsA0R<2Dwh}RuN}s$A@K2 zElhveR&brTpTiI#!oV)uxQ%_wt+Q{gE!8lQT%zjDc9BP`i$S()#pcE4^~d{UKm8TF zy-57fg}e=~zuqbT-#p3r#mkq1SqAeTyuEvHbyq9z%Hw#rI-c zPTtDNc3oXu-!f$4J2y%oRx z>o!{@e@+3)E{;^l{vC^TKRCxjmPs z>!+nY<`Dn;;scAR=@qf)$+pWlau=L&4t-h|s9-vk@ujlHvk7VCs3$ zwR!34^=l`8Of6XMdBS$jq1X-e{~2%Qlz!z6i42WaIM%?;Z#20?O>-)H#4#?$a~4TA zQ!TpO0}~m4X@7~Ri+AMQ;UF}%ChVF#hofZp+XYu%3UaO9^HL{$h&2s z9rqP4I5BA(?s;W1Wl5~qyBasC1BVvQFqWIM<=FAVFF$@fsrxYC(YK2eA8c=4*jaC7 zSMtGH{`Zm4?RTs1$4XznSN**6>uY&0fwjN)M*a?7o4J%>!!*6fTh9z@-oMGnHQ!Zb z)gY*OWKzT_@8TtSJZt{03M~(e&tD&qytQ5#a;J9C)68 zuQXk`*j;C3aDi!V?4z#%8ZwLb{^tAe{ln*-p(~Hc-}TRX6&U#VpkZcE=KBm`9?OjZ ziW$#rKd%3DH`kFBpr`Jo4FFv}D zSH54&a<|o0{BgPWW5FwPTs!YO+8nM{*FL#x&I9K~6D>YSfBO-kVPq(1Wo9N-XJR4u z^Wz1N7umPBz5n~>x!r&M`@3Ji3+2E6{lKid{I(_WDR+03uK!_hVe<7Y!3@jiS57;> zp_l*4m1{qq@tzBtllf#@$*y-R6+5gVzAc|u*S0D1I>Mp8KD_GDnLKN%tt5}^e2%txoNVgvdfbxC zef#?3f6xBPzW(p@)$5}w&)2RtxB2toR<&Fq_3NmcU^6w21Cy3hZ8whHgEsX)_h?}MDSt}jyT&RNeSEU?k%@3-LgF(Ihpl; z&NG37?o*%Y9GM}1exc*NCk77=a9Y*AbPCgwlalP*@Zbs8)BD%1u}P-)7Bk-6av`Q! zFFIqTjgb+z^zp3{4x1wLgay@JG<4}qUAnWFeaTEWje|eVH{4M2=D#K%kn7odclC>P zG2MQtBn64ixpl3y%)8V|sWDYE(fttD zdH1V~dT#~d?<*f~%TN-T$hcOcy==?Yi*NST%{n|Ud_70?;s?SaJC}va?@GU~QMmDL zs?S%8J2PT#=gyM)HJvY{b{~_*gO8>fCwd>pzSjH8XJwtArD$H-85Ggo;-aE{O;$DB zVdKIp425p$%G|px4efST8_85ENX+?Ds3G+8RD?m*-?rt~|9|FxX``kKAj-~aO8 zwcnU~d)IW=yI;N5W=>@(xxQ3>$D`}IyuA69|Jm<3b1>J$?Z5Y>OmW}2CCO7B*Y3&u zEVt|RyRBcI=hxbnmT%i|l$YZZ&pYd=LPzE8ullMh7k~4-Q+G`Aw1!~6hkIOd?c$O> zM=zQE{W7ikrEqwxTW;>uE&m^A)V}nNU)rr-XC1ov!ui?OyA9&yypP3Z*VVNK8F}e# z*=Dxn#oh<=7O^MXzGho;kX1Y|vNc?X-++6vaI(y-3Kpq1nzHH73`^#$x_5qCNX$Bg zMR{tsu6?wes}g-)UiF=wkerj&Gj$iyhC9mnrv>;NnjAyAddx)9n@fzY1=l*y^|Gr|8D#GM>o3R;

Yr_``$n#?_P_H|6dT2AjR zP9-rNYvmT_P2b?G+~==)*-ZPD$nIZ)eJ{6fWZ$4DxqV*W^5p18A0M8$8Xo_5mB%RqNH!yzJD3Y?7(tkk)1rtTn)=#ON9L!8(F@+)?}P+)u%T33&-~d zuHyT`XSE5;Q&66F)`d0Jy!>2D=GLiCq>}=RVna%8y}SdCMz88FY&+$*I{xLGx|1`E z%{$eXOjii>U7l*h_epw*Nof>sHn6c)=r_Z%!Yi+;Z z*?vj-{txw83NDP^U#>lrp0&7VX3F%l-tqq~nZNYEUm>-%JR~UC+uE|SA-YEB@v_L% z@-{YJ+1G76yv21BvTu8Oi=7X@9FsHkCtK@*ZFk!>xobKm7p{`)pH&yRAqx0F9C{^|Q? z+U>)gPc|leIPv5Cr8w)m*S3T(OpmL`+`WF$n;)MpPy2Ds`n~KW|92l>-I?05MMp(u z|I)J>-1GbM_WjKBI_9i%jA;Z+FwgbFEDU#jSywr zxxz^PG?(p%55grs@5daO|9tuKZEqJ^huw31zVE5;m3udJJU3LBc+Hi48&t+D9=G#M zQ~0`6*0!omnzC|oi-nz&pXhUM*ex&ciB}*>!Lf6p(1sfaJ4OE9of^MDd)E=e4(fa=pViEkHcu{L!-Kg{2? zN?BxyiZHJ@xasDe!}oe+d)3aWaF^@l=O*drZ=QK3x8&5`-~F=Q$JX!rwdqXvya(AC zzPnWvt{qs^7_)Q#Bc`(D(T3U#e{Z!NPvv~3ZV~tC#))t0H~BWJ9|)^BfA9H+FSG4WT z=9U5`iB_!-+zN?D?=y1os>mGg@40k{b@R%lOPi*OaoE{#9SxtvQEYA@wt;76PD|_$ zp58u}mmd}u{=0Yl#m;7R4I%HqQdeE=?RHT+HuQ@oPXEAWcFpW#`tBZ6tA}h`SEOxx zedf=}rgw4AS01X-YAyIQ>(a999i`tNJyc`u_Oud@NS=BiJ#?jEzLrC8beHg*Jqj-a zj-3rsnz$|bqDxARjfsd%_ZoTrw)~kg-8ID}HE%x4@BH)k`n|nrq6%B2uie@I>&LCF ztAk!&TRU@F;h)oymxCDJ+}nHGF85{E=E~iA(sRrmN^?%``Q&@&7~fXIi)yP6#qrzz zyrQ$y<+=z_p>e8t0prF=!J;-t_x6^ENnPye}Y_S zSY^ileab0mJg?s7C{1~;d)a&PLY1o~S5|DABPig&YsV&b>h<;&)BcNfr)J)p!>Gls z(LSF!Ja&(m^K>ptwYBL7V|ITNj4J!3#21@&#evhk@T}I&;v=?QxrzZc}ZO7)rHexp6cpGo;xiASKr;VQ08Z$-w?Y|?%@&Avg|9>{^>gw=y`>WrsYUa1A@c;CEm*Vn| zv!-z|yzY6LUjB)#lD*>Zt=qGg%=6Rx+-2jedT>LaL-W?c!(xeRb8}Zt)YN_2$S~EL zTc49RG_+K9ZS?lWUsbS`&+Wv;Fzj z_2;b?@&)^Bj?NOVvgV{5U9KYL-TM23!;K4u=xUYE%ePbQQEt4xb9HkADBXEgKI z^$e5p$KT#c*Oxq{Xe`iw`~czKW4Q^v$YfMTxgZea~(U35@jI|L1D*l}mSg?#?~iA;B^$I`nWNTb%Ob zHeKGdjTRySAD(Rb6!q(>zWhX%WkOn$>KMZnQm;AA^zELev&7f`{gT?C7w_Gj74n9EeUPGfaINz^UpfY?%1uZtR0ZtCl&3rzK|E#Wf1m&+M; z=$$6VZtgWRZ!v~%dBbq^$rjh+{)uVlw6*m;cZHnuR5P~hyDgk^_j{|;#ov!UKH+ye ze*C|sjM=^owa0(`-}UDc|NZ*kZ@0hO@%P)*$L05SPKx~*E@t;TD(Z3=qfYETrrrke z-!=1oxpqJE{Qzt6k-M%QHXZaINv@veF+e>`Ah^-VY4^7Ur! z8WyRD6(ZYZEWQ>=$<5xbtC+xWr1;z%Ii{m`4>BLmFp_y*u`l>W_G;Ce>C<-{KgHaj z#Gr4}Vg1n4=I4>%Eh!(3Tn(RHt>uyUtCF*wvGL`#Yt=93T%YTweU2fTm%F;$`s!7a z3Gv^z?T)Nue3r#9f9ZbjmFh04XDybp7Mo8g;Og&M9gsTtaInA^O(uPoxl&h>ecp0y zxf2$?{qEI}ustu1y`JB3bFCCIEtKHu3dOgjC`**gP^Z)jU%VCUHuJ2dAd}T&Wd+Mys({*B; zuIBWHHuadq+!avr7N|M7pmUbhuJ8NUSMFcl&lJ}#CB51*=fmfCQ9t>W3_R~^%8u(L zzIprZ%_JcSx0suk(%uMXW%2B&NPAs3%f4Rm_=n1kU-thxE4(G)Vaz`s(~M?@2F30B z*0>nVXTF&-Pfh)?iJ6gJWt*t>xd{eG7DxU6>Tp(R@|x++JfgpEYi-nQivMtb`Jd-O z{#t!p&r{s@xm@rLJ6Wx%ztF_&dfuJ|{CkTyezq?^(Wrjbqpyk4`%d5d%FP$<&pY`% zq`z8iHEZnAHyM*W(}OR~5baj|^fBd^gVM}8C6UfMQvPb|%_q;ye`mkv`)%>qnuEFa z`@b&t|NBVXTz=p4c~^}Ke`{}8mMVE6HoWG?s_dH;b?<7$<2;x@|5n}2pRHB=>4=Kb zyfddvWZT!iGL7Hc_>BL|@^yVyujX9!+U7s??34#Ll5F!ME0-%U{D0HCUi{8}p99Sf zUW?A9T)*RAzNT)TM*nRBKy`%;IAy2h<;I zR+#0og5lBGXV273uiburHEqWU-Ef~Z+K0ad8NELG)QLa7V(zQITs929@|XVo(3KJT zeWQ5Rn_bEm!v6ja>btDB&$`(^rmoS%+NyE-_MZhmI+hyWO#k_P_UFjr;Cp4;e*OLS z<5;h>@cO4!zgL&~X0sMtefs~$x*EIM#h?jpZk0{i&~dV zxfpi;ueViM&6Kb?X7jDAqi?LxIs_RoLU60;r+}X8x--1grMTRS3JymRbt z_+?O6i%T9CT@zylXpV%t=v9V&%HHi_kWG5 z?{a6C>fd3Kligk&653$0;@H!dn|*c%*t@Yq#g)-uJY() zXN1YV*|ziIk2zhG_iI^vy}z%0U)@30_j^7*-~R7Sg19a$=d;yH>7RB~|rdVSC2ICP&F))wL_O zsZA4$*{3U%8Qg09r1kY(;k(wd)Vy%vdrpU z$n)qp#b;YCaL;U=a$o1Azr*Dqw!&(Yq@zm0=UtN@x~n-&-oE6~$$DQm;p?(DOMX;~ z*FQOAT~~KocXs&NsLCEzyN_P?{?GjS>H3y126jG~4d-I&&RK3t)thN<5G_z*l(Oi` zUQ-YM$igN5|2|A~z7)ru$hO<$l&{22Q!6V^W#>dL-?o*jH+TO^E5GgW!$7%bDJ+tr){5KIv&hdr2b%%lfjB!i zYfINiJkS!qM<`O-yPOG{FG87~V=HQTboqT!IT z?4%tz$Dc5jd!?U!`MpTEXldc@R7=+{i}JX`Htw-baZY@eE1sFYvT=^a^iARu(pn8q zowuEI^2z*<)q7??o_OV)uC@7_+3Vh}Gk(2&edb%nguM@a>z|!ma%sA$`PJ&Q@83AS z%TC>K`_tiozn|m8ZY)08Z=p zZRZ3ps>cRgfo`14_E(d%5 zkM8{yzw7T5o%Wai_wua$&C=Ve=Ch|~yxorhAQ{G z_Vift(62*t!bgo$XPGiv&X#`$30)y0}__cgzot(Z_UrGD47xc>)LpB6kn;8}ZjBiEOZb5m|rPn>b-QtjKk zy|JnvZ(Ke9%pgSNs8juwEuYvwTYi>2oNY7tWXiXhx6dex$JSoVZrhobw%6#j=|Tp( zs;A5EO+LLWeC~Jg{KdxSBix>brnc_iJE8lZ&8ru|4ypcWi!5iB1WlDGHSSLox%0g# zR9*MRy43A=j>x|Jc&@7=n8Eat$zsXuD;0u*e{7^u9V~T?9~Jeb&U!p8G57h8dT*`C zx6jPquWc(OyZ6Z{Z>3`)A{Wohiqzk=td@@<`{&E_r81{?Zd$nR-0kbvwa@HY`g;4( zm%%%pdS!jji*wkzQ7p2eaEED`OsiS=wWTk9Z!ejorynNOX}SBxrL0*(v%S~MJN;>* zm_e^k$Hc+_%a>34U6RfnNingu6zue6JA7MReQ|cv{4{!zFq9uo=$JSsuxSSr*7qH@2S)~kR^J4 z|5ES5p!w`2VQZ{!|J);*QeLMr`E-t{Z+fxSw3~9CeQ$pKIBqZZ+d1y^%&+^i_o|67 zT%2xO|9#?zwWXm~#p8=kRlZiFNR%<=Uvfy$~~h>WOB*TPkYx*&$fCUWOg$s zrlxW6xw(JCX3a4Ee2HyMi~IuV%MT-L&%_<7<6|saZuByp=lEt_K_9u=2Z8TD@c7lG z{Z+i4?ZPM!TX!>bJ{Jqq_4ty9@fQ#Lv70%~yVb5N-|@sr(UQZtrwWBzR&}4(I+JbA zogi7hD0}6D*}DYU?lIh|i=D*%Wy@prdqD+XEl;0$T2vkRV0+5uo4O}cW<4%@zc8R< z(fnUmTwmHhGo2l2{JPa}<>lO;%+kg;_ek=&x6VHIocqL!cbhhG*_~Rc6L8RLq0@~< zgX3~C^*86JTGSu8`!U69*`;HX3%!;IP4Q9Hoaq;&#oSl(;jF3&Z>SF+&*nKit(i47 zO~>4h&z<=2l3S1>Wfsl8TJ46 zhnT4cXFl!}vAWSRf$2|?rr5s{BhO5+8ktU)Dg0q9oh=*wC)|s*5L(uG((_DR^MTvS z>TYdq?QQ1sEX+Q|ALrwbEq!re;`ZDdJ3jW5?|psevR>7DYrWqG*zf(ld%o_QvVYC% z==n1lubo*F{hD3Z;f=T)6J$o$Mwn`N)p{q5VEf1dIAi-*GJCORLV+sxi)^?Sbcn>SDIzrDNn{>{zB^EVg& z&U-%d?Cm+c{<&q>*57|%^J(_+x$bh6XKH>Nj8}iZ_xHh#xAS)XzWD#&zufz~Ubg-J zcfd4$U!mbDp6T&*JO3X&pOAKT&CIXv(enR3sGs|PD?I;1{@qQ%Ew$JC_MY2({#}8Y z?cX(<{~3yXaldBGZ~LXA_@{-1-c@qgZI z?Y8@Mv47g$AL?h<%rxB`SNi&G{{A&j|JVMD=f79_eDAqe*4H*{_`rGDjb63Bg zyC?VQEnoBhIbYBJe|*3G)64q(FWsNV6`%e7JihYj)T{MxiswZdXQ%y@yWVd9=j3L) z&ofuof9&k9|9F4@=ehrPJ=*p9-{(26*Zto9?fd@!!J+kUif4n=gKbZ{c4iiw^RMIe zf99XOiq#AZ4F9`={xUEyFnGH9xvX( z_wL+d=xJzYy>|Jk&7GTf94=qDsCw+sA?{oEA2Qx~^n~%=qo<7bLG z3FEcvw;0Z!zr=9(;4y|PSFSUzTE0g1{P|0}E?>TO@6MeE$DTZXw(7}~=dJf2Jc_(^ z>#o6r2T#Oq+`Pkg^2BNO6KBpbUAl3H@xkL449AX~WH@s82;~C_{n67GA09t@_2S{-E=di|EsxpNnJuU@{v zxOM#ow$mriCZ9TS`rDBs$Nro?d*ScZ>o@=0ynFxet$Ppt+`9Mh@3q@^|C~I3>Cd^# zSASo-efPuV>$kVxzWYe`{F(ENCl4QTI&_^3C7pFJAq7 z^7Q%NhmW58yLspS-(#oG{yl!??C)b|&%HZ)`Fg>&oqO54+PaudA34&0^3Z`FCk`I? zbMf@azc(&j`gix{&3}&{KKlRs*^7TKU%vkT{Ke~km#$p@d;H9WKj$uAUwHNA1CcZ5 zFEJ*@BnzB9etgrdOBeo}J9hN%zHM9no;a}o-=)(h|6V@)7ii8;Mvc+a-u;J|PM}av|ZS@bIaetBLBY`S=m0Y_vZ=QH?+p0g^%~5|E>q7oj)rbGh&5HP!5EJ+} zH!bGx)(z|aT)T8>^Yf?A1rF@q&Is1bz`*e4#Y@HsogKXUcJ5km<s+yCCWc5U^m=P&t=AKDMs|LWyihWQJYaP8Q&zv{-V z`-iUIxO@5Pl^gf3T)Fo0@|CNf&R@9r_1xL>FRx#}dHLbPr=`!Iz2Uff_aR*W0p|bz z8yNrpZ(#WUp8*{+{{PPa!_5ExGoaxH=KudS7#J8N7#J7~kjj|^PMGfoj_#~!Qh#vo z!IOvg9&WvN>rU(C3m1Zq@81t94yod(b*ncd-MDq{|M`no{@=U*=>PMVZ~wn}^Zwt9 z=dWHrfBtIwu$)eCYV>1BZ_NU%O%R|MlxP{@=a-@c;AYFa3Y? z0J$?N6*~VLU?$us6d%^yho;*}jc z_xxYKe#8IGTX+0FaO~9oE7xxRzjE{T|9g+0{lD|*$^ZLLp8db~=;{9lAo?MQ|Kk6H zr!W3Le)j6$z59>v+`N5n$;FFTQqk?okB=9)bL-yUV~3CaKXu~d|1)PV{J(hV^8c&X zuK&Mz=idJtx9|SHeec2lYq#$Fzw_Yn|Ess|{6Bs1%KvS95B}f1|KR^?ckcebcIV#z z^H*>DfBNF>6lC+SpE{+!Z278FuV20U|Ki!J|DQg52IG(KKmC9G^7a20&tLt2^7PsN z`wt%ezyI*@|LeDI|G#tp;r|n7FZ|zo?9~4=7cTt2bmQj#-G`6{`_?f<7wU;lsn`1$|)cOOCV z{{Qa1hyPEVKKuX3iPQgg?%NM?`@4rPJ}4oZ4Pu`;cI@e)o!kEJT)+1J_BE^iAKba^ z|Cu8P|DQW{r$ zb^iagTlfCofBGg6WF9gO42+h%a`x=MTbC~Uzj5LG|MSO={y%wO-~Uqw_y0e+fA9a} zdw2amd2k=tzO%;;{Xci&=>L0n@BM%H zy7~Xs)yw~HT)+N*`|iE}cke&+fB)fQ{|_EL`TyLRvmZg`q2sKKy!wk*ZvMY>@6rFK zPhb3h`{v#MSI=Mke{}cm|GU?&{eS=F-TzPTKmPyt?!*5NZ{Poa_xkPsM-LwT-@JX- z|4rL>|6jd+^Z#Wl*ZeB#AU%q(Z|CP%Y|6jR$ z$^Uh0R{h_-Ysdfd=g$4Ve&hE4yAPiHfAZ|r|Cg`cg59xs!}|ZrmM#CkVBy05a~CZ6 zfAZMj|2J;j)k86yfq|i-y7}~^sdN5M>FfT#WcKv`pWnUz|Mum}|F51u|9}7X?f+*^ z9RGiK@9zJ*wru#nam|YVtClVPzj)Dt|MM5j|G#SO+W-5Gp8UV>@bUjAPM^Dd_3Ax& zbn~mL8t=C@H2iO?E&so4!TkTPo;~}&eapuG+qZ1`zkAoN|3{A=|9|1q)&JM7-}-;+ z*4_X2?mqZ`|Ng`O5AHqqfAz}M|2qyG`8Q|f#@XGA7ICAS4dRy+m%gtk%KKkYkokYz z%2oewUcUH0CeG%6T%6hexMYj}kx{1qgT2iD#{|0n&rFH?UtLl9f9mAP|M%?L^?&>3 z&HrD#c)1T`4j#;sk&z*m93StnciZ;=XOABIpPpy>KQYPte^RQ&|I|{;|M6+2{{vl2 z|9d+a|97=9`0rt7@_+NX)&FPqcm03$;`L5EX2YdoViNVw96tR2=JKOx-b|Gu5u{~zAF=l_RyAJ)JP!NaJps>*rs@ZtZ>OQ!yx(3$wZr84+`V`Ip_ z+V+TlC6y8Xvr;1eC&z{SkBRX6Uyu>=f6tCx{}1fi3MvB^;V~92)zQ#U|NiC6|J#>N z|KD4d_`jzj>3>g6%D;~4l)u$Q3I7YyqW&jG`TdU#^Zs9+75)Ff-rfKA?cVkO|IhE;{{Q6G)&KXeUig3g+=>6E4(|TH zf7^!tS56=MfAiwm|6e|Q>BD0zTx#*E&3*?@T%L6F#D&F&Ph8k~?DVChC(m5DaQecH zTW2rdesccWowpaS-~Dpw=KXg!A3VQt@5!4(k6yfA@#NJPL%1PmjQ{`tGkmcB&+viq zKf?zGeufVWj0_JL7#R+LF*Cyf26l!9Fy@ES$b5T-1_pbE2Y4{39R_OLI3Tsd8Zb&g zG)E00?#Uy^FFm+@=fJf~mnNJ8^-uQh)n;H|V5Wx?^U~7fZr*V3AA3b<<_}-m+z1J>Zi#T%Rh%znQGo^1z*yCrf|F7S$`TyoE+x{Ove)9jt zt2h2Xc=+`H+xH*;zx(j{|J(PU|Gx&e^&ESU zm#v@nzjG;96b8}z#&Nc4b+x;@bJ<9$4{RBfBf|2{}->`{(t-7%m3H! zKK+0G;?2LukDorcbLZab%a<>g9^Zf1Vb!WtJfyhk@WG?UjvP7ufA!jR|99=${eQ!z zt>CuW;iD)2U%heb|BZVO|KEM|?En3zFaAGz@#_D>XD|NWd-w#5?}O+EkN-b^{r>+m z5PtRU|HH@6e&4=*|H9SF*JhkJb|P-$s*Q?x+{1qE%*F2q4jlTwdhPoEdw1>rzirpP z{|Ap8|9|D$jsG`p-Ti;<=I#GC?%V^nSFhc=`~Ui#d;f1gcno&ay(iEAU%z|*|A8YX z{_i??`2VT17r^ajP&@g_%eViZzIgNh-h(HnaoJyyUt;+T6sFH!{=a+s-v3+IZh+fl zH*ehhf8+Yi|F>@6{eR=uo&UG*-1~p)?tL%@xdnu8g826z{@-`x*#BLJkN@9w;K=`D zCr$5fByge?T7!bUcUMN?Agozj~+ky|KQQ%|Mwm|`hWAz-Tyak-}!&z z&fWhf&t3d~@Z6RE`wtxg_a83axb=Vcp(FoKT)6b_@r$=G|KGg>< zfAi|)|Mza+{{Qgd!~aj8Jp2Fr`OE*$U%dt8!T;B8-1&d{!qxw~4xRXa``+XKr!QXz zRRticu;O*gS6zDf*vq?KX>Ht{}cOm|39*G`~QR6xBNf8XV?Fe z2loCyd1(Ltvquj8KYR4h|8vKW{6BZ%$p2e6uK$1h?B)N5PhNoA%eU@5{D152ga0?~ zKKOs(@{NZTlNSnOwHPAExp~dHUvHj0{r}{~C2+m{{`Kqs8&}_p|Ng^A{~tMd`v0l(m;Rr- zeEt80D>wh2JA3Xu#2V~mKxnAhfn9t5zj^-r|NEEE|G#_j;{V4tZ~h9_1pg+J$>>2nM*hRU%UO_|AR-*|G#+o=Kq_w zAO638{|VIA`v2*}r~jWnd;<4*ko!IFL4CqkZ~pJzv;Y5wE!+NY*t+Zg%C(#RFI%ShM;6iX{vG&z?T{|LkcK|IeK{ z_5ZrnEB+tYzvuty)2IJmx^mY`6Y#A0JE4yUNlv#`aPoKHq|MW={{?F*| z{Qv0Qz5j1sJpcdX;r;)Y&Y$~#aL?}l+cvEIzhTAV|0@^G{=aC>wEuHwfZRCg|Kf%7 z{%_g3<^TSJhyNctb?*P!OV|FNK7Z-|iBo6(A31vL|K-b<{@uKJAESQ^b4p2R-HEQA zN&kD=+yD2q)c&8^+xh>~+xP#UKY8;1!QFfRA3b>Z|H-2#|DQg7_W${_7yn-QWD zfZ2tOE-S0O-Bj1`zqz{ne{)sw|0%t_|G$0w{D1F`t^eoEoBDs=j7k3&&Yk&x`I1Hd z*RNamA2dz_8do@Z=KTM&=P&&S)zvpZ<1}|4{D1WD3Aii(mCbWkZrDG4!775|O+`he zA1aCp{#O;{{x2`c_&<00jQ`(1eg5CuRQ^9E-u{1llIj1rWb^;AspkJf{Z0P+I~o5E za5nuP9pv#pCoS=ReNEN>DO0BY-?VkZB{j~ou!1qDXg z*%>~C*=dPcsqr1Fmn{AN?c>M)Eftynvm4C*$HkfcPe``-pO|IwKe@#Ge{81l|3GJx z|GtjK|2^%E|GQWl{C6>u=pS3YX0BH(d55}z43o1E2IAn zWqJR1ZrSpGMtAG~XHTB~|Ns9#)_yg}9$YvfA>IG@-aY?6zIpw>u_Wq$X`}W3k`l-N zIT;TBv+^ANXBFH1&&ap^ALnoPKhn?Pf1roWe?NEI{~k_OVEcD%-THreU-$p#&z}Eh zU|=A5dy@Ud~qko2!cc@87fM|KbI6{=am|vXCwswPmK%t9~2KRs8yngeGfq{Vump!<|>nf|dA6~!y|LwEK|7(lA|F_fz{%@%Vxx@E= zeRJsls>bmDrM2Pzvr{7frzeK}Plyiu9~J8TKQA-p|D^W1|Hls>{l9<5_W$qSzW<8L z4t(OxwYBqK+<)-@)uX%ro67wEPi)Qj-%%I#zp*~>e?wc?zpBQF|E1ND|Fct~{--BJ z{7;Mt1ozAHvg7~H?r;CUbLYPQd$z0t_5EMtvj>-4S7YPGch8^ye|YWu|GLbe|1EhD zV7fLt_+M2{(4V4=puc(Pq5rdz!v3cxg#3?>@ckbb;rqWZGv@!2>3#oq?%wl%*S4+y zKYjT42$voB#QR!X4t{?39$fysxOe;i!)q7*-#UBj|J4%*{#`z@>)*M3oBkczwDkYB zWi$V;nA!b*dPnvDj;fsh^@Yj*mrv{be{k!D{|C0N1J#o^@Y#b)Zr-eU=WgA5_W$9N zSO1?pfBXOC>kt3mzWe|Nad^fBpLXKWOaX(#AFff0B;sXo}><1Va_@P+-00V=30|SG71B3>#VHhM< z-@w4|AA~9{U}DfX1!%4)0ePH473{PTM^xtJ>0LN=`oYE1XEvQWa-?a` zwrzoHmMp;-_Z_SO)7#RK^YYcZ|L@;@`v30jhySl%zWM+3(UbqTuit!q_0pxC=TDz* zJAU|Z(56+Z*j z??1bJQSfBEV)|2J*f{{O)K{r{INS@D1Gfy4i| z@7VqS<*WDquV26M|L&dp{~tYi^8YnxzU}=N@c7gFk6*!l0?m)TdiC!Aqestv-MxMP z!j0=UW}QECK6U@j{h*?TeXvU&Yd~ecXa=u$aTw?Q)LWtO4o!oP-2`hVlP4gYuUJNSR^vD5z#96$U2@S&ssZ{2$U9`Cw&|Iz;^uipND49e%P-u{2` z^7a2m&tCk$b@$%?+jsAQ=UMOGfAk+TCin8~$N#UO_}QBe|DV5l2kt*UeDw6+_3JlY zoj-SR^YKGRs&{PI;y7i>6q4KRtCz0Y_v+32{~OkC{J&%O-v29Ctp2}e*Y5wzmaY81 z@7SsTdyk&_f8_A7|K~4U2G4C?x^@#hK6Cs2qyM+=Kl*>+>UGc<&41AN-MyzT{)5Kq zKz;-H>EYAo|F7S;`5!cw_U!fh|5tC_{eSDhsxqR*azC*|UuUNbO|DGeq{_oj;=>O&G*Z<#s^yL4YM^FDh ze(~o2lb7%QKLz0zZ~s4j_GSq&?$1d~)W34^+W&X2-~YdJ>+b(E$4~sfeD&u4WBc}l z`=iH>9Q}Xk(xv~m@7(==_3Cx-y#K8`_x|61^yL4g%UAzjzkTQbUCdpU~*Khv6ee2GD(0uf{^B4YKyAB$cfB65-y$9g61=nxh z{trqopgaIt&j1>e1&z&u#)&uV*!_RU;p6}J96R-Y`_7&JFW4D{3UoT!ILM?!0~e%H2?qj2{@fyyLJ2j z&D(eXgVuY1#+r8@IQsw4`K$kTA3XN|)S1)&uYkwmAN)Ue`6_sPcl*I3|3PW<;fr@w z1l-QBW5pWBJ6A9M2jQ!iE`!G`L1Rgvw!??_kTo12w|@n%u>g(zegXRh#0QN7e+G+x zgN_4#`Tq$t{tBws-hKH0_U(JHpB_Jc_W#l2XaAo(d-)$UKC=JN(f@}}pZ~vl#mfI@ zE?xP5=F;W=XD?j_uLaq>d(Z!iSFitn^!)8kV)~66mai(hfAiY^yVtM$zk1>9|6A8C z|G#(Z#{UO*Z~cFG{~ma)$jfIh{=WgujeyoCeEjnN)2DC$zko4l-3Y|(pmA&n28n?% zNFB&OU;lsn0O?P>d-vi0>o@QJ-viBi+;K3vRckSK(fAfyr|JQHb_J7re4gXJ^ zzXZzfPwqT_E=DNqLGtUCEnD*N_O1WtjvWS%FK=G4^#8UsEC27?y6OMXeY^jkJ$B^( zwTtJ#{=0wc#{Y+R@BDxK;KBcAj~@Mh@$}jMmoHv|$Nb*E2el)<{s+~)pt11Jpgzzi zko!USGk8r5#2;V&zk2!h|H-o#|6c~JN4R?*G%o`lBR+rm>i_#sU;e)L?43QxZN%Vp z%a&h#a{u1{lLz;M$LtSm+wyQ(=@tzH3MN3(Oo+W-5vZT^2`_m2OEc5MBBc;~kN z$M)^|f9mjo|Cdgm{D0%ph5vW1U;Y2!_O1U9?%nQkB5B=Y=@96)vJNN(JvG34-P`OV`nuqx-)IOAFZSj8Zr=QV@6Nsd_wGIT ze-E_gR!G10G_wIa^vp*JNF;|zj)*R|CWifEMV>Up;gB|LH>q{~zD8^Z%i3TfpHCnnO4N8b3a`@BfKC zyTI{qeE;76r$O@whY$V-tvv$GC7eBe7(AzN^2q-Gw{P44r;lf^-hu0+2Tx!AzkUD7 z|LeEz{l9kO*8giaZi4HD8@KQOKY9AXwt5og7{fy&b1t1a{r~mTC;vfn4$p62{r~d8 z?f>syz4#BBcesA}GC2HRzj*!s_4611pFeyAUUT&D=B@v?FJJn9_3Y{Y7fu`p=biJ% zj{LuP@;De@ICcC#2%kTB6ue&S;^iyd&z}8%_u}dQyXQ~*zkA`-{|~QU{r~X#_5Z%E z_W#rS+W(j2W&E$HDEYs2&(8nbH*WfWVE3;7FP}d9|KaTi@OmlGyaC96&!GOhfAa=- zjn?%G=l0deUSBApfyYvFI;?v z>^?&5)P&UYAUi?xETH+8_pe@n-Tv|Q8}Pi#xub{v@7uKY|El>j|4-{``G0Kxj{mzi zulc`n(HwAo{rLU^cn$;BJQyzKwng-ieM-LV-oH}(Jeb^P;_u=ofF3QenT==#58 z#fJaOR&Dyfe9e~sE7xrPzk21W|8pjH{qJh3{@>qL_kZ@3p8qSC&i%h-$4{R5f9~S7|Cg`d`G4)sqyKjwJ_ptJ|6hXUuik$A|K{yS@Z2qE-W#;m@ZtT3 z|F>`1{D0cyiT|h1n)`q9)EWP$O`ZII!IBmK=Pp?Kf7;Bs|MzU$`2X6~tN$-wyBP;_ zBR)DfIJ~*DYwG`*^H%(yJ%8o@IrEnNpFLyN|2dO7|IeQ}NA*U;aP1d;9;n3m5;NJ$vr|=`&~lpFVT$|LL>m|DQQ`0gO+d zy#OAk0QH40UB34J>a|<{Z`{1|{|{$IIr z`Txo-JO9sKvHr)5rR$2o!?rNT5kVIgmS3)|ssGjH8uY) zoje5|_XpLV1(`Ab%j;ABSCobQuPBQCUs;&^zq&Z;LcGd+`6^6Q}8|DQU29^7XK`S13f`~M$4eDeS0tJnVz zpE!4C^1{_7L^u~iNl{VR^YW6C|CPlB|Er4g{#O-c|F0;__+M93_y6|g%V78K-L~O> zu&c@c@Br)oG2v$aKgh%Qe}I$8e}6|~C^r2c=Hv7~JwEDx zRax=>{=UBdixw~czkTOEa3A;3{saFHA2{%T_qOf-U%h<&|Mly)#TX7FQlOxybaH-9 z?$-RA%+rNA=?_YB(>~{=#s6z*X#W57&RwwkH!Pq3KQ_kre@=(#|ELhN|IzU#|C0*M z|Ho&T|4%A6`yZcc@;@@s_DaPQv#vnKZZUp{}%|5q`}hABOm6?5m1q7xE#2gQas+7Z+4_H4ruF}n49owyO?Lm&^3DIJ zRha#ck1_ur?r!lv#LWUcAMfpG{NKag@V~2#;eSU<{r>^3)?oMV-@W^PS9Qt%RSV|) ze+?>!sqFsfxRl5_6DR!t`S~-r{Wi0!?tf0c<^O_ui~o7)cK@@|?Ej}_*!)jRvHzdb z=-q!!aJ+1x+dszMVcenZP@9Fs8$KCF~r;FYH02k~3D;CZD ze{k=<|4Zl0_`h-aV({9lSFhd_Vhcxd#o`ju^H-n%v_uQN#S+S!i zL_7RX2y*c5w>&Ho@b>;G$(F9Mf6OXkl0zi#0S= ze3yyM9ps8-XXeh>w{gS&-(SD|fA{Rk|K6I+{|%jP|EmgJ|5w+#{x42;`(M}W`@ga@ z%|+|L)Bj{)6i7H}5|tk?U4$`ik-jS0CHC1ML2{Papm7C{6g^((n1d zvEAW+Q=7~G@?_WlO}+mA8*9S;H}-}8FRu>$Uo#=>e@j{s;TH{g3o@`oDSY%Kyg?ANhac$kG3Mw`~H=>;HfK?p+KvcaSSqRaUX@%z=IX ze}DV_|MlYs{~L3||F`yf{ckAu|KHmm@xL^|?SIpxfd6&nA^)2uhyAatj`&~GANoHx zE$V-EO2q$+q=^4%@uB|{q5}U%hx+`F4)^_EoEQH;E5`r-*7d9ZpE!E#|M4S7{~y@C z(oX4Jp(@`(RcJz@XzQbFM#`9C8$;(uBKXb(u> z|L8E^|MAg*|I5p={^utI|KGKF{r|07j{o1fe!>64dv^T)`2OSnSFea4XCuZ>ZS{3O z9$dZh|Ig3g{~umG`@byS{eM}a=l{wS-~VNaUjIuIz5iFH`~R!T4E|eH68^g+E8=f) zN#y_B6wo@B$p4vO_lNyYj0*T49q#u(DK6xHb$Ryx;=~|un%}$c!2bf%|zj|!{|BHuq{y)2S^Z%1O*8M-S zdBy*|YZw0Cx^&k6HFGEYUpTS#|D=}k|5KYw|8HI}>HprfOaAXzKKK9WgF8X%YW{!t z@SUi!25jy{7fXpvQCl>7&j0(5LF;Ya{RhpxzkUOnqyGH=$ zfBw?#|Cg`d|9|bylmEBwzxaRm@$3KhpS}J6@Ws3Tk3jh4`~Oc~efa<6^@smY!T96< zr>{T$fA;#*|7UMN^vC~?U%vnU_|?ZfFuSQpb8g>$Msnl!!`hp6AGg_l;FRC)V;AH1 z9y?#S=g67n-G@&0Z{K%x*7kjemhRkpc>T6Lhj(n>bLjB4y+_V&-+ScRt^>#K?LKt! z>8?Yk-t0bn`sMB;r!O8nb7l9@OShLEzjC+#%(aIVXKp@8ICt+EXndcnJv^XwO5h#o zjUX0ikr6*=3l+ov28MdDcmo4yH#!4o(W5+Q=Q;xe10$4X;Aa4fgLV&r79}Fnpn*To zj^7WUz~pCOK%wQKe0wNe&%p2iqz;|_4;6>e^$ZLLpz4UC|3lP++zV3A4(0PB(I9t% z_#pRFlZKg#jRu7y$UYDaTBiltK+pgRSLpd63`C8%fC2(Po;P`F{)t0Jt{mNeV9DNX zJ4&{#U++A-w^sZ{GiZ^WxS2Cl4O}zkcQFzYC{M-#>lq#M&eK z_EqoRvc+T7s#Qdf6AhuzVP3m(!+X#i+Kbok|G#?k5xl?s-Fr~^58Y4y>h1rhkDmU& zee>48YZos)xOnE=n&U?gSM1%n*J=Iw^+RY^BWA2*rKD&dI(YmasNRF%5C36n&p`8Z zVEp#u|JUz6|9=OX5B~V&KWNVN?b~<%L3;DfQLF>N2`yu~>_RihAbN|PU>o?C_x_D{YspF>-_wU>Z+WUg# zv?KcX5uYtxjUBU}K7afF(bHG|7tLSzf8XI_|7Xsc{eRc)egC&_+x~y|j-CJ4ZP@gG z-@(J+`HNe(?)`uB_7gadynPQ^mk7ac-hTqG8GH8;5+2|%dH?zUtJm-TKY9G@|J_@6 zKU}?h^}zYF7rRd$I~lrv`*zUwVEDN&_}oZKx%smfUIFEM(0-?xGiLwabMVOj{=NzS z_Z~U%f7_NV|5q+w@qg3yz5fp%KMh`Ya_Q2w|4*O40iQ2$`SRue*RNgwf9vM$|99`+ z|Nr9kyZ>)LeEt9C!x!*+P0$`$5C-KNFb1u4eEaeL^XISsKYZ}`->n2?!EsH9XkAf+r~}*pTBwoUPt)sIp_=)&|1Pf|8L&94c;Sq=kCM*cke%f zhRK)zZ{CCOXYd|f&_3NaptY=^b*-Si&9C47fBf|M|J%3k{JC`g!rjv+PcJ`m;84-F zb(?G!;W!(D8fhXuCc*Xmxyzt4YyNNAuo3LfrOQ|RU%zqF|7|;V{NKHG+y7-NR)hEc z?mux3ybf;H{=@%I96Ry<-owZLuiU=-|Iy1g{~tbo^Z(f!(0<={|DU~n_y5_e*Z&_s zfARm}lc(T)sn>7b0`Hl%Kh+hfLz~^|JyKot_hxq@+Yq$R2efaeM zsdE>==kT1nat*xB@7leG{~vvc|37^C?Em#!cm7`iufx0X z|H_r?|F7M+{r|-qkpDmafASjC4|xv`3y|2$w;%q4)`dQM`3Ag}>gLTm|IVGg@Z#9v zV;lEu-&wY1#R_W@=FU-qVNyr`)>p3~;k{`7qW?$FUi?3~e{cL#qU3V{r@p&Jqf5i@d~uo@fCQz>dm_k!0SDa96Ry<;K|efL2JW6 zYeGTk0kp;wyj~TQHlXW0pM%z}g4Vh|c@AD5cj4Tn^C%u8j>EKk{<7DgHE(zB-2cCP z*^2)=cJBH=XV#qm`wk!Ze`xpa|I3#y`@jF#ng55*T>QU%$Ik!HU%vUjWBZQ(PoF;j zf9dMA|99@*`wv=!d-2j0aD1IQd+z_US8x8GK6l~&<7Y4aU$}bX|LuDZ|6jR%?>}g5 zBxsNN)NS_`i4G-v6LA zfVUnz`hWZ3nWaqBMD1|Fah^g7+qa z)|KA8dk=iB(Z#FR{y%#0=KrRxJ0NRe4^Z4oi zJ5Qc~*J|Fpckln9V<-RbJapv$`D@qzKYRK1|KsOxKwUPH`?O`*dGWVy-UY8W0PQ7* zwg2Bj*RQ;P^A@~z@E&Nb>9ZIAFJHLy|Hh3w|IeK{_aAf?0O;(jTeoiizjWow|N9Rg zf%Egz7q9+bymAfft_zp0fY$?Gxqkis4Ny9{dk=hW0%(0EXss_K9XtlNE4J=C_-u?gQLF-iS-v7U9!>0cm_U!+E`Q|N9 zo_YQF@f#ULtP*BbclLx=x3%_<|Mr7N;4>Q@fYQU|tKfR!^3`kLumR=!1BZ_M-*fWZ|6M1}{@-)rEO=ehz5{#y z-+K7y|M|;T{$IXz2V5RpzJ2%qnoXPkuLsRFpE?6tcm4O_lh=NPeGFH@cH_dS@HOi< zt(rc6$^V0gj{gU(6?*&b;EqwAnSL(egv(D1+5SL3|*)E2{JG9{^S4q_wN6H{r3I;Yu9i5fARY5{|n%>|Kk6J zi;+-Ms1l>fRTOVrspFyC)lyxi^1l?(rGUpWt6S9;;>MabDI??7uP zKzrID{XNiHQIP+?eEj_XEBL&JFaJM-&whZd|NZj++h@?YAZV>D2qV_fg7)8i`UF{{ z1X{cO{{4slZ(hFzuLTCJ1AYWr3-j#7|LfOpf!jM*u3Q73U9n~7Zt%MDojdk|%e>o< zp8Y?4?mXzMjQ?jYUI4ET2F3khP~N+92Q*#>TCc|j^BXbr#$_wY?%lZZ|G~|x|3T}9 z@7=ui|NiY;|L@Ameg}y| z{0|x@g{&h6@j>Dc{ORN8{}B8IvM&p?miYBsusshRJ_estxNFaW{}-;^{=ab69Pl2M zHS5>^-*xcN|4m!B{XcT{-2Zi(xBlM)?TDUa8~(4`x)odoJbe1{@BJ5;=j>tiFq+`nB};FD)*3&$ zbNm1PtsDRE-Mr!d!pRf5m2pk^!wr%-;`Si*ES1+6cpSK1&ljPCe z+y5Wky#ro@`uN`6|4%^cupdA9|NQxLaM}j-iQj|920lR6VT1a9ACdh3;nU~;;Jg7% z3!pLv4^qp1t~i@Ahj#D$zj4{(|GU<&`G0ip?*A+2%=~}i z;C}Er^gSEa{y%4 z^Z&v92mc>GdiwwAvzPxt{ht?a-h=xbK5=T#*`M-1j(f{i< z?*P?v{~tbk^Z($Pi$*a2kV;1fMdqJBaq|C*M-To#fBf+O$-TS(FP%Q+|Ir=W{~y`4 z^Z)XhGyb30zxV&4?OXqES+?Z==_3dKZ&|VA|EUA}{vY4J=l`}<%faViZdtwreBR97 zP3!-kJ96;<@qN4hAK$+lyk`8w-ksp{13~B0oC2MndHm4-Q%4Vh&&j!P`sDw6cR}YL z-uwRmbWYRVd*CsHo1pdFx9@`2$Aj9GpuJR}HXUgH)58~_vzkDA+TQ)&eBi{7+R1as zp0iGfieGr=>Q(T1dC;2q*H54PfAQq;|L2b${s-;BxO(~&_}raS2M_!|xo7wP^T&_; z-@Ihu|MN!=|39{8*Z;j6*Z#kF;@JPKE0+Ghbn5v3{hK%Zzi{FRILuBQ*z+G0|0nkC z`G4`$@&Bg|?)`uM_|gAojvWAprWcKXvR>GXv<@a8e^4sy;m-?eepS z_rdG!L4JSz^fCBczLyW~{s*nUfA{Joc-=i{-6g2~`|kCd|F51t|Nrvw)Bg`|-3G6@ zzkB`K|Kodh|G$0V{Qo06w*0?x=EVOqhY$Tfedxgd%coEMKe>O;|EuTEK=@}){Xc#5 zAY?86iDO{)qX+lFdm%u5fvY!ff%h~$0-a$6#i0EK_ny4^fBW&P|2H1K_`U);L#|JCCMV84HO z{rdm9RV)7Yv^D=} z`Tyw7o&VR*o&A63>J{*rO*bxI_9$M8MvVFqb=Ka{@=J| z+yAXQcm3aW;1GDM>DcLW|Ib{!{QvUJJO6Loefa;{t^5Bkp1%k>yXgOga~JlL>~W|D z-@q`7=BoPtZ=OE+{|>xg;o1N9&mRB3fBEeHJLgaRfBpCoc+bLzH*fwgm_7Y}UrXKp zsl6@#OAE69r>7?UpT20$|IJ%B{+~H%(*JcUSNz|!ayk4ACeWIB5dQEMv5&57}R^V%56;JGX85fBwwr|CcXa`NqJ&K-TzqaB#$&IWrdizy0v}|ND<$ z{D1ruboM={z4i7#sPF&o&HMi!-o5+(>D>qL`M96nz5frwpF#ZhAO3%S|Kb0KH*fzx z1??xkc;Wxe3unP+!hHg-Er+bZMh*v*uy}(M1}|TO*UoO+w(I|ftvmj&-?IJx+Krq4 zgU-_ijRAl#DE>iw(B6<0tJnSCzIEgObEi-KzjFENzw6hpOOYJ;3=9k*A(7|$`e*## zx$o%zeMe6HKXU5g|C8sh{Xci*_Wvul9{j)c;K~1oPhb6i_VPV=o&z*C3mVr4wRJyy zfb@w#{h`kvKmP~g50Ep!kk0`F`5%Ts{s&=DI`|0MkAW5jyZ0XWzj5o%|J(N-{J-i_3X9{Ydw>b3tjuigaB zE0G!m?4hAiKW5He`hU&F9sk#D+WCLOmOcMBZrl5R^NxN0x9vXgf7iZ4|99^@^#8z- z{=a3zs{cE-ZTi1^ z_s;)&L2JN|p89{{%%%TlFJ1qC`Nm!F9+o=~Ux3?ZPhWrh|NPBI@R&CEOoVqI!Dk}A z2kmKj^Wi@zpS^wk_WzLs2mY^Gy6FG(X;c5N*}UWb^f`$96R{`#*Lf*uU)$VTI)|z5cmcJ1Z8Fv{+~5(<^S0WR{fv5 zX!ZYji`M*~zi7q(`EwWipFe%#|4AM7|5vYC_5bLh{r@*_So?qBoSFY8bhrQSXsZ9; zR8#T4t}Oq5ZE@!R+QPK|EtR?dCwJ8TUox}r|ArOw{%_r|;{Vo7>;G@xzWx7>-TVIU zJ#_s4QE(c%_W#1wTmP@#e(?Y1{ipx$K6&;3;d9Wu0O*{$x8SoSZ(qOh|MYRty2K;k zeHv?4Ed9S>{ks1vR;>6xd*+<~%a*VDzY4TZ_~^d>w{G0}fBpJxlKVaZ0ikKd#dZHD z&s_3<>g*-|r_WyUf5yxO|EEov_J3M`&;MyX&HtzOcl|$e^!Wb|uit>{!FR7-{eScF z`TtkXp8S9QcIN-VGnf9KxOnaV=}R~MUAXn=*yYPl zWJ&dZSV(kVOWUOXT|HC(cXdtp-`&~szqhUBe{XX=c+XL9Q|14elPCRuaO*bMzo5GA z?wz~f@!i|EZvVe~=idJZ_aB1K9(?}fIr!W`Q2Pc{zJbbr5dH++g9j4(@a{c$&(7$m-1yl&h7g=@F`pSx=F*V(JKU_Gyun6OAnNL|?4*7v`?t@nR>OUM8A#>W4h z4b}fU8!G>I)|dZpsx16JYub$euO2@I?^^=J=atJB|6c&z$#CJq|BDwd{J(VZ(*KJW zFa5u85hQ-;|M?4-{+~O4@jqw|?EJ;6;Qs2h>$m^kyan3p{180X4LYCk-J5sdwbHQi z9~5qHUcLVR>cz|d&!0T~|MWM}4YZEWoL-`v>xzqzjNe^X8Q|K{ql|1H&}|68hx|5p?j z{9iDA=KoJ`-h%hcfyM{6Zrb#J^@^qc*RERrf8FYp|JSWu`+wu6&HuOW+ykB$Jaqi@ z|0Ac){Xcr@?EmAZ&i+3IYPW;-c0u=af%bZxJbmsz2%kE0{{NZtm;Yb5bPaq50BC;~ zXbj-hi`W0(y?*x}6h?1ez4`z0#jF2MpFIQL!!doy>VMOguANywb0!y7Pmv&)pI>^i zva0TXbtP!8SK0si@{<4cx zv+AS%XBFE1PfM}+pPFL*KOw^Ae@u|||7c&^|M7vY|I?!a|L3K}{jVs>{omSH`+v%$ ziT@WZTKa$e<{kg{96AQx&kCAD2hGHnx8)Bn+7X8&WOEdIx&S^SSp zvG^aKX7WG4*$A?C%*o_`fFp=)^54%9bT+5?{~!+z;AUwhgkc=Ea-acs)d-WMNVH(}IG+|3!JZ z|BG|8{+Hxt{x8kT_+Ofn`oAzU@qcM)<^LUP*8KnR`7<~S?p(k0Kiu8?e`2c9|I|{5 zzoQdO|0foh|4+y<`yZWT{6DSM;(u(0$^V3Gv;Se?M*l;C4FCH(8vXZkgzZB!{_pK% z^54tR{J*=M@qag4Sh0DOzQu?am}j#uU@_W z|MJC~TO@jskaCW+v^2Tw>@<_CtaPuO^pu3cthCai?BuSDq?lzjRrUW4Y~2FhcLa+6 zOJ|P#k8m~lpH*l2KerPU_h$c73eEni@o7yZ*OTmil;4zkEq`|Kkjw(5QIhhMI=|r}pgw?;HE}>GS_%`*!?~ z_B8#U*KGDbF~RhIw71#+{2q({QT`VHqXW$UXE&PvPfD`>pI&A8KfT=ie^S2b|MXgu z|6v|x|3h3M_k{R68UF{}72;)Y^xwnI@V}dl!G9+Uz5jNm+W+lMbinPTE$deOKd^W2 z|J~a+|6j9o;r}hGSNwnd8g!oTTWZHYPXC8R#s{=DHvPYR;siMUzkc}efA7|{{}X)7 z{+CWL|DTd%@;|}P;(ugX#Y$ zFZ2Il?x1~umf$mK{hUqygZ2Wt+ky5o8vJ*$*8lHduJ_-;Oz(eHLHhsA>sN#0e|BHj z|K5hm{~K2<0nZ=4en~(7hsPu)_qMkEzkBf_*#95jy#2pz?UMgVKIZ?6JFNd_<(vIa z3$gy6n`iq!GsEG3da2F-lmz?#X?gblvuo}CXIEJLPsyzB^@pXP7=zr4@te?_~UxWSs_SuvFOK0}{FHUj!U*G5Sza+)we|e_s|MEts|0VIB z{~OwU|Cg5e{Vyr={a@Yh^FOD+>3>eK-T(YL`~S&74*%l=9segs`GEIwCWL$c5BGQa zAK-5D-wzZ9ZkGRjT|bo z-&YUs{h!iY_`jyi^?%z`_y4UE?Eg2_di-w$r+>Hq?b8GQH`RvyZ|w>HU)LY}zpOO; ze`Qzb|B{-p|G6pQ|Fe?Az~^zN#fSY*0`H{__#YYS^FKV$^M6>N=l{qMFYw;%mh#O1 zdvH%==Z-g-t~XWtib>Ep#8VK;s2YbhW;-p z4E^6QDe`}5b@>0>H0VCcq=^6NiQ)fK<3k{Oal?H7M}>O*kB#*EUtXB>KQ-F#e`j?b z_*}`;$4~x0c?>i+c<}$hozQ)`Z$E6Lt~arp784W0U0quFd*6n&|Nngd0p54~{NAnq zoh9-A8*BXj_w+>nZ_11K-`kn^zoE(>y#KguYViN+yx{*Wlf(WuP7eQHlo$5Dc2dOu zqLPUJx!`@UQU5bjBL8P3h5t{94*}-^&_3j-5TF0CQ33z+a}xfiMhE=wYbg1DaPOY~ zr%#;xfBfk2|DgCkynEaKPoQ;3?>{cb?qceSrpKjAH&oUBKe~O(|35!|{r~;_$Ny({ zum5k!kNDr#5d44U?6m*ARhj>%O-cLTP#o|dwEwrQE98H5Zpi<(sS*F{Cx-klD~b7E zJtgRWQDM~o+|=m*St-%reaz`ep!g5{pBxhe-iI9(<_kWfzO*>we@cYU|0(U&{|_J7 z|Nqo+kpGYUKX&lY|08>Lfc^jO-N!l9^(l7Kl9QA5TI=iopV_w?yk`}(PxZx}YyTUw zg8sKu`2C+XHT{2Ib=LohU2*^Ga(w>R6ngycnicWCz9`~f>$HeJ^}XT$DoUdM*G&!o zpO+Z{-v^zU42u7V|EclNz0l#l;QhqO@ge^!%Cr9`1iAg6)8G96*uew;H?BYZf8L@= z{||0i`~TSfUEqD)@85o!gx$r|6-|y$cIa(w`G4uiL9qY-{QUj@@wK!6tCGF`m&Ut+ z_f1!&`u#6Y^8R0%;Q7BS+2?;nhX4QStk8eeMPa`yOTvGZW=H(3sEhuemj>EL9rZsa zH440s8kGK1<3s-^MhE_n3HSXU6B+P7Eji+UZFT7$* zeY&=)QvgAK!m$!tP?~il!x|CC=#Y`G5D~d9eRM`?Wv6ef|IDsiXg|9NG8( z(*AA#Pj6rQ|M2>S|Mx7L`G3cPN&mOb>;J!F!NmXjR?PT!eDk9JXLm09e`@EF|A#lu z{l9bh)c@<|_55EtwdMcJp6dVojfMXkOVa+A=fwWcPYL^FC@c1Va)9ms4fA{d zA3w0?|JjqL!RIm@-m?q5mIO48{NdfF3hMe4yJ=}DX$5m9^!^8}UHJ9=C-~e0P#A#m z@4x^5{r(FN7m(PWpTGY9{Qmv_myhrNzj^lf|HB(s|KB`w>i^}VhyR~HwDbWe~eb2y0D?`E$=+y#N3573l0a z(3$LCz-PpM{rvs^w=b|g?~w5M1*#`N``&;4hL;(je1nWZ=SP4rC`^BT`|%%yLHpsq zef|C)ydVC{xBp*0gVvFP)`oui|LNmLu)jfTZ9#L(-#>n*>bWSm{GXp)*uHz;vHxc- z-}!(3>b?J$u08mF<>tfxS8qT5fBEL)|JUw3`+w{H%m4Qtz54&)$?N|QpT7D3_!(%g z!8`Cg`SVvF|G#_<+Ped~2l31QcOSm~|M2PC|Bs))|NjKSU%vnU{Pp|)PhVj82Urd+ z|M@$d57PJkZ4jlWx|L}?bhmM{7f8@l)|3^<> z{(t=Jwf`s1-}ry(;;sK@uH5;5?%KWo7j8WIf9dw)|5xrl`+xQR^Z(Z#y!d||gde{A zf8*iH|2H4K`hV;3D=>Zi;miM5AHH~Z?f$C*T<)clIOB#R*Lm0MJuAQAz){1E2hTWd zJ9I8&%fWNW+YX)0-EsI_#r_i)TK1hh*SG)ZnHjr|oLac&=*cxZ4!CEv`v@B1-~az9 zrW-)+{{R0!HEG8G|NnymmKhYW5DYpe!h?Z1+ zW9OZt`wwp1yLEfxwzV4q7tNXl+OIKM#xXE3)EAXjf$nextqFVm{KfxA_wWC|dF|T2 z^QTU~Id%BR-a~u$_w3%fHER2+RqCL7Ip`5*gUOCbo&B4hJb(TF;SDR8WwpoH!V$h`<7k*UVzTAdhz!E(c`E7pSyVF|Mi=9 z{yzt;=?C4X^%}IF{KNm3pmPU6=bC`-SAX~E|9jB=9iTm0p!<~HfBygW&HMkL^G)vG zd+_(>wOdcGUb?*T{OPkbM-Lu#9}IVG5lAOkrE`)qV=i5Q>>Iv({nr1vv*-Q??W>$U zXU_kv+jsomxBtL@(4NHOCr*Ly^8xKocnu97$eQ4f{~Haroqg|68_f{|~xT?e@J#|JSWp0XpLYRBnUMtOwnrcJtPq z|Db)b;PXMi=carC-**QJJJ337Fb0W#fSex!x?>A`e#*lqpu3R1UAlDX__G{-Y=V&s(q%yvF|!=nk+QJOB50_x#_z z@8JJ^hfn<9d+6BzU3(AwU%q1H|C5K0{6Bf()PK+!GA~}g`TzXotN%|y=c+t^@&Ep# z$Nxcl#ctdHtuwp}S_=!ln*@C34k&Dp&Q<~4aRyn#56YvT{=Wv@%k=UM_-umPckcba zbm7vwvnNmOJ$CSL$F40~g4Qlx4B9_W^YTA6Hqrj*p%edKzx@C{vjTL^#DSwH{!i%Z z|G)q6k^k$~tOlR647#sjH|V^P6KDS)ICUO;{>0j~8$jpf{J(bR9{7GS(76fspS}A3 z?9B(rxhro#XRmo@2ml z|9cM~|G#P1{{P2Moc@0kbS}lsyZ^7>xDCELTc-pkkjpFDs0|IxGO;4^JN=kZ^;d<}dq3y2L0H%Qok&Sv@W z{|PAnzXF}l@)3My3+N0C*!e7vA3y&ON@Ew!U;2Lh$njJAcki9BZuRQ01q&7syaSw2 zfz(#hwBhAT(0#b?|F2oG61={0{l?Az7tUYw|KO41{}1fk^?%lkS>Q7?b{#tYf9u|Z z{|_HJ0=`?|?t>@)4;?!C|LKd@{|_BK{{P9d7yr*)z5+gb1$5`u!xwM4S*FkqLynOrr(aU$xb1~ojfAZ?h|EDis{eSfQ`Ts{xpM%%7K7IM_ z|Gh`gz?zl?LH%z6Q8 z|Gjwm_W#m_3;*xlv+w_$*>k{m=j=In=>PEp2ma5VHT(abBPahKIC<{>iZyHh-?@GF z|COuPz-Keuy>}mcuOjF!_XjWDfYUJ@2Tz~>KXvZ>|Hm(0gXJGQd;S0RlNaDHd-&?z|C8r0|37)|68MghEqf3A-+T1f z|2>C~{y%W&=>Ie4&;P%E=iYzNy+jXRyoRPpr1M=s_W-^Gjk|*G0(?E0P#VD{pBa^? zv}N7a|Dg8C+t=^@@7%iM|LF@?|4;7i|9|+{>Hn*jE&G3D-@gCn&YT6`JGcMPQSiF& zo44=%zkK=Xf6#dy&z`^ff8x~X|Ic5){eR%#q5sdGKL?+I13J&**8PY7Z`}j!S-kWA z(X&_o&z!&b|MAP$|4*Gc2To(){p(MjgYO-C1iFLl%-R2sUcCOlefPfqdk!A{zjOb= z|66wM`M++<_W!$&9{+#%^tt~l7ccsM`P#MrpnFsAJbv{5=KcHs&tAOr|JJ=n|Bs$N z4?a@|boR~j7jHr5Pu+Y;#$EHU@XAd|kG^>R%Kx{ZvkyUMn1Rmqdh+c5^GA>WgYK=k zarx^1o0qTr2b~pl{p$7qXHK8}52~X!t>5_n$&;u5j~zMs|H+dl|1Vy?{QvQ@=l{=N zy8QpytGEA8pFRgZy9ty&z;)Q2d;f3Ux%>b2{RjVV-+%c3@{ODSAHRI}AG9YHbg$)! zQ>Xqv0i7Xp^*Z=GCD2)XJCC0HzxUKR@EIw)L238I8Sq(E=P#c7f9b~U|JNQq{eJ^= z|Kjx<|1Vv?4&J}DZ2iXn>v!z>fBWI1|4(1O{r>RTYh##SNuet$+Jt?4e7Ne%Dpx#v z_6oe8>E-h`;QI|h>(@WL`vl$#2U;J2!9tfBW{s|1-x< zfY0;-of`%^2L!Z-0CYae-Fx@I>FxI2JO4px2y|c6gQqY4-vouz-Fx8sCof*T3f>n3 z@*60v-F*T|ch|w^WUX7j>Hm&{NB-|PboBp@Lr4DaI(+OuXkY1(BZvQAyLbOT=qw`8 zIXRbZ-u!?0#`XVauif~+1XPC{JpBLg=`;VIym`Nz)WZb-Ps&n_Az28=>+xq|L@w4D`@b2Bm|IeSi`2X<7pg`AHeXuWIzyE*X{6%nhf$p5!x&P4rV<*r3U$St)|LgZ3{y%;3%Kxjk zZvVe<^*Z?8*TW}H|6jdv7>PbOf4fMcn!M z1sp~oaZtFRW2io8*h0?i0iE3giG%mx{hS}b`&3@Ne*6E?9^S*}ul_xJ@s8{= zCqFse;o61s{~z4G{{O+9o8Yrb&K^Jd|Llol|3PQ@+`oPE|D!uM|3A8Wp>|4$!3`v2_NbMRRsptcfdkMl>+xmKWb0;NG`8-el}9Dn})AI1iq>+>1u zT$_)dzWfJa@VP!8zWo0P8bkUBx-<1N^o-n(|6jg(3(l9IySpx3zVZLmnG63x?ThWZ z_WcK)`?PHJn*VFJZ25ou?1ldi9zXwo|M}ZBL|M=h|#v zvjTk9&-T?T{_o$h_5YDQJOA%kxBCBy1N*^uc3!`95q$6BqdTB;kM8_`au0Hz&7(Va zA?F}HeE9$Af|CQ^Yd&nPx&xw5T@(uXT+&lLlfy*&aoBH0<7ylnTe|!7>{r41| zx7<=)w-|Jm(c^m{zuf_!gS2Yi?Ej$iaQ1K8@_+x1ZD6rwv#0;xyK(*hL%VnUKfZVO z|J4iTfzQJ^acDpI+>;}FcKyG8@jN)(ZeP3d|1tC|AP@}-_lKbKlJ4L8{}^;0(35BX zpS^ek?)!qm?LBBb8E$c<1%=1^51{*OLFE)A4IMjn>i^b#NB-|QapC`l z-3R|~*?$Dg-+kox{}bmg{l9zvG5EZ_CokT8yZ!V%Xv_$f6v(3cTH3EZ0o@<`;Qs%o z5AXlqxpvL}MN=mJ-?nPS{{uU={XevG`~U50R{meRaNhsJJGX=H^fEi#Odsji{;jCIP2YfyX=&sUZ`*;7pbo#{q+gC6DzXduw@b)e6 z-M$a*-uZw3&Mok{LH9xI`w#v=ClJ9CFq$=_y5t;7vTGGA3T4ZO;&&)Y4Y>)Ek;{UO|yZ;~EyX*hnP3!(|Si124 znL`J__XY1>xBCCq)hqv>04EA&^;zs z&Yt*xboY+`XAbWFfBEdG|A%*N`wx=8eC8yWeev}1|0fUc|9|7!)&CFf-T(jK>1*&^ zn-8A6_<#T5Q}DTBH*enlf9)D*Z|e2`H*Ven?=uITS$yZwv;X&=z5?GzfB)&L|Lb=h z-d#ImzB9t7sR3Oir&9^{r}0s$N%5Fegocf4%%P+;q}}9??HXnN00wMxqA;> zuH3tJ9ej@0t&8XWUq62ae9jptja@%~_Wx=`{=aeY{Qt8@4}5WVOU);X~4ja%}PEQ^`{GXkY@V~pM=6_#X;FyLcl_VJXFqtZ zbGml(|Fv5W{$IO!_y5_Gr~Y5MZ~=5i=t=TI1OY((^!TWRpZBj{|Nr*cQ}|g=Z=c-% z|KReu|MxDP`Tz34eef9R|6jg%`7Z+l0|$8_1JM-_6q;FCT>by%oyY$lJ$VVfpZ@vtH~(M1dJ8_o^*!jE zsJHL_e*~Qs_4eKWPjLJmd~Ou%yeQDwQ7;}p{(tw;JDXFVp;P~lp1%11^u_D{FI>C(|LUzr|8G5b z{{P;S*Z&_qdksF18*-mD=w67A|KEYmO$PPnLE}82vs6GBbY=($gYG8>ovng|k;4bZ zhJ_J`28Gkdw}`XWKxqgRM(597_`iAE_W#@V9{#`k$f^HZ_Z<1ZZrk4ft2gibzhWKe zY^l}%mn>iPf6>wv|Cg><{U4Oi_HN(&|H7G5|3T+V-MMkYiM)`3=n4u6Ki62_@qf)G z(D`0_|8Ls9@BikV2mWu}edzyo(76W(j{ZMz?DYSmr!V|JbK%K!j6ZBPIYL4sfAsXtgx;6F<^Sq++y1X!zy1H}4cnpT za_#)TX~Ty98&@sp5s$2k34I&>9Xf2HoZM=|AW^W)KF27wD`v^fYwi+D-7; z!_z19{BLfk|KHry^uNBo;eS_m-~ZmOj{nnV&-*`R`mFyGCQbc6W%|tjv*$1VzkSo% z|L0B~{eR>7jsI7!-KrxiWEdD2yaNOE!z1GUPo1&&|NJHE{x4X%?*GDN>;ErWzTyAk z73=>mUAE@`(gh3tFP+u@zrM2Me@%JW|BAw#|0UTe|4Y*2{#WKC{%@k zUH{iCnel(qnuY(jZCLpqbbi+!(D_~a_W$31=-B^5$It#he&)*mGna1uzjWjN|Lb=j z|G)bPbPxR-@Y(v$Uw;74>%DmM@joang7WgKHy{2#0*!keJMw?S%BBC;tXlnl{rXM+ z*KXMIf6?M4|L4q@{C~}+t^e0=+4+Cjnoa)~Em`${#;p1OH?Lds|J;c~|8IcLuev## z-0<-Y40KIQ$oM~f*3$no=dSoaYyOJ=vlp!VKWF~(|8wRn_&;mTyIg2pfIg8D_*{$Iax;s2?VhyU-|zUBY&C5!)0ozVZkqp9J4V^!Jz+LD6*l?55# zJ?XUtssB4_^8ZiossF!tR^R`1%jf>zxMs=!jq6wc-?C-%|81bNDnaMO9X`NIF_jvx4c>*g)c9PSQs!zUmhI5IoC^#8=^i~moax#<5i5T3E% z|Fo$y|4*GT@&B}*j{noToBmJfY5Tu#`%aAd3Uv16``54kgU&&H4LZ~L=@UpFYPf8*+<{};}l`oC}YuK%l+Fa1Ab^2GmLptG&2%Kq1s=KZh8OZ#7*o%p}LIQ@Tr zbJ_oSQ#$^yUOeOf+La6buUWnP|GIVS{;%J(?f<&1yZ&$7dEo!fgD1defE_=7?f=

^YZuo=*hUJ!4H2v?N zJnw)1l-d9LC(igkX~N|HlX`ppPws5~Ke@B<|KyH(a9i*6p~K*_kiLKV^8Y*ZJTTC? zU?BFl&#?3FL1Xow{(t@O5qv%*s4V#aYTvv9wVOa~z-RwoJbCgTbWS#CT;tY_>;Erb zy7>R_!F~VNu3Yhd`lN~fTN~>BSCUyvUEKR+$*e_3wI|K_TK{}Z~J{?DA& z|9|e>S^pP+&j(xkf5pa~|5t6<^MCy=&=}CM|2vPI{(tb)#s5dnUj2RH=Hn%2?%w4m zH+({aBO2=(dcfy|b#_nu-__aozq`HTe{X9O^sKO&|GiCB|EKiz{=abYB>1c_Q20E1 z`V@Ts(KXQdjMs1ezXduo4Ak$s|LFgdM^FDhfBO9Y>ld%V=c0njT~NIR!=U|MAhD02 z^EKas&JBC>|MkmP|6e_S@&Cosr~jWkeE1)9Ha#fpu3WtM|K#yw|2J*i_HnJ= z>i(A%7yQr9&;DPKpZUM8v-5xNqBZ{)uiyHA@%nB57p>j;f5Do~|L3gQ{Al*-&7f-o z$qgE?zNo0UsVyzN|J&R9{{om10|Gx|AEU}iV!v9kzP5FQG!X@xoV&6V~ z{(tM*mH(G6UHpIX!iE2rFJ1trfy;AN_y&_}Twg;Bb5ouH#|tAXps_Y6F4J6?^gY+5abx9)afwZr{53|LT>? z|IeN|{r|wBL;u%p-SL0Q(l!6*t={;5_R0W1gU+AI`#*ci^#2cU-Uf#cC>>lncjo`zeFy*V z*|+ci{sRa8?>l(#KWGdOv@Yn-@iYIAo;>^i$f>jck3r8GJ8}9PcuxJy+4JE0SI(Zl z@c+!&3;$1_J^%mY>9gQ-wLs(RXU|^-ugka!8dJXe;Q!;tPr+x5y?g!cKd2oK3O7)g zfzsQH=P&+)=C1EQeE5Ia`fdMbEM5C;^5V6ieRxz`6P24?w706J@qbNq?f?4f%Kr_O zW&i6dO8(bZ6#s7kpGQ{kzo;PZ|J~XT}8l&rgi_Uz(K&KG&Ol3ym%@2T;bgZ zkN-b-{OtdO$4~zUo!xdAd=}Z6|Hn^(FeuE*`H=uJzAfWk6wa!O&h%P;#lXyyAaFY3cv!vf}?WrA7a1N(;et zOLcM1|LT&g|M|Ij{};`e0Y0k^RQ9}o_3Hn+<@5gsI~o0tO7#98m+ARGA>Q{D=9AdUs_o3zcfGhe|dh+|B8YvFfPkW|6h`u z`oEx{tm_$^Y1B^Z#+_rvGD8LE&Wn zKg`eUe{{UX|HyEQ|G{2H|AX9&{s)52b8`Zn<7WKd&&l||uOkSX{P%G-{qOB$4nEh+ z+tK{LkCVm!$RMBp`B@qN+nQVcuUxwP|Kd5*!RI<1K6L2+ft`@Klntv^faj)Py?p)u z-Mi1aR0s|XBMOSj8uRiBSLbDCAIi_px}Kkv{b@DG5;$oYX7fY zwDAAWPoMw)`26MntEZ3u&+KddAL?fCzjT`A|D0Zv{}JA1|09D<|3^ib{LiYl`X3o( z3{FSM)h7Q_D$V{Um6`sJOf~!;k!zmw5_Uq{fHXU5?3uDl#g|9d!?{dco5 z`tM?6_}|%5|3B!=BWEka|49*k|7T9@{J(eC&j0)O?ET+SRr)_KJ>~z(B@6$*c<};! zHuSr9?`RS}7y$+m0G$mdS(uiln-CkDR8!sXf7_~+;Ip7W;q&~_18`d|+|%%X@f3^y z>1F2sBYaH%r#Bk^kBhMQAL(Q9KdZ&^e_Xu9|D*!T|EaZB|3PQPCFU9b&uB6GALMTQ zKgh-OzrV97G>lCCdx6e{vxA%o=4xXAJ{Qi`MC-qUna=;{K==PM`rH5S-@W_);R6T% zH=4&T}yS4>~u_-QEa%b{;7G*qQ45w>Q)MALZu^ z37Puh8~*Ryyy5?b za#L~g|I{e+|D}^n{wIf<|4;I>{GU^1^*=em>VHa-_5bW9i~mW{Hvcm#?EdF=*#1w; zHUFQKZT3H>!~B1gxB34F56k}{ZWjN+XR5iF{Rf>d=uUAi$JOS) zkDKj(A2<8|p3b)aU2M(%hkM!opE;omeBQ*-Lx=xQY;XNPwX^B}`epO~zXqMp|N71U zx6j{d!xKFn8PTz+QzmzH{=a?x96WsPUBCLjG|B&ePKwq4@(GszOIs}d7pB_&uWSRg zf$aaMh1&klsj~i`5Mueiu+`;%QLp3wj4a##DY@4Fb6afw#|47Uq_h1W>udWz!rS(L zn794^KzHl^fgZO11HB#p`*}P4_jR-Q@9pmR-^Iq{f0(D;|Jjp!!1dQ5(3wo2I}bLm z2cJy{4xcw~|G$3y8nnNFjv)iFDlQ>y)y%%W|Br552cOmU^Yf?wcdlOgUz*_iKR?6j zf5Q}q|D`!j|10ub{?|=#`kx!^^uI94`G0wr`~So+yZ`w$F8_<$UH+%1*#8HeXPcR4 z4?eRlA;A8Be4x|+gfP$l(Sa`igWawE2f17S_jd)ITW9s($Hn5mw~O_ES3C3n;hwht z=T7SdhtJ+!yZ>j!ME>{laR0w%@%;a9L1W}^-v0ma@&iR<%n;v_P9~*f?4L7n!vB{K z9)QE=`=^ipZ(cn2zcAM0e|f3X|H?Xt|D_48|I0F5{+G2m{x6RA{9je%^}njq=YMX3 z=l_~szyAd-uKzQW9sg$+*#6Hcv;Ch0KGVzw}=G&uZE4srRP9OCppCDP}A zN=)GYloi1^Pw)G` zdG&J8xqqOwpZ~tT{t7w^fg-<>qd7Y>_xaN4Q~!T^_Z}QRU*Es|f8p4H|HZMc|LdDQ z|2I!}`Cppk^1r&+^?y}^%m1P{_y2X(e*f$G0{)lhhyHKu5Bguz8}vUX-S2-{i}(M+ zTDSk{ksklkqP+g6#RdOQjSc>v93A*S5p*tKh{yj>AN&7-p0@vkeH{M#df5N>a<=^+ z?d$Y^`TQB+b3sAjbNI}u|N9T@`@e17%Kz`)y#EhMKmR}dr%HdF)G*4=Dfqd1&P;II z`S;gv|G&I_^Z(TT?f*;ST>m$Bdj4;l?Eb&1%>I8(h0Fi?W~cwf@oxW{+5-MJPYV8D zTN?hqWop>}`UxTb^D~40SNDYdFRlyupOYN+KPxHhe@0^1|MY~=|0%H{;B&%aBmDkH zg?RlB3-I_K?C1VJz{};ow~OunxB!>`s~6Ate_#*f>@?8Xd7!%_c5Ynr|HIo4|KGfM z`|tn%|9qtSjZ*b#p=tc(MWz2XESwKcJAb}?|NrUrtN(|0tObWpW0%|i_Ni|F+b6mF zZ*TVf-`45&za-A>e?zP9|K^_H|4kKP|68Yo|8JTU`oAbQ?0?O~(Enw1pfd$QXX=H6 z&y&kY1f8iC_CF~m_W==1AEo^)IRV6B84a>ME=MZC$qHKPc_|{`URXYM=&6;cK|L|DZ}thoOL*$Myi;sX9}S+nf_!TpHv0i8{_Z|er| z*=!%)fBZxZ|B`A(QhbtkM`QEHihQU5cNBmSo)hJnwm1eMWIVLtys=N86C2mUX}OZs1s75~39CG7vU^(!IcKgUo0 zKYrvW_#C(W+c$yFE`0y~<1`h(BC1f6@Bk`Vg8vLfeyMtt!9#=M08d$z3q zf8^kP@I3RTUHkqY+Pn8Z`0Pv2I*9k5>2~%tau}v1r8mu<(EI=DiDUo&{QC3%&#&MA zpWnLle_m(l|C;pR|BcyU|66mz{x@X@|F6#s{9l#g`@cNN=YL7O*S}H_PVo6(k{Iy6 zBq{KJK~m8F+@z5IISHZvvl1aVGcojkMncH{wD{ovNznoSi_$9f$rDb1wI?`(}z!Ikljr$c6xHg zqyGKiu2)f2gO`|JYFX|78Wq|07+E|Myp={XevG%l{LH5B)!V z^3?yMM~?nKvS;`IGl%zs&(Qn$;o~8Cg$c4fS*ckI7f+w`|G~9u;P3&3(cj;HpzPoO zL2S_Zi9f!6{{Q~PlmCydUHX6h#L@p34(|PbcF(r|CwFZ8e{A#W|3@|~{eNKfy#ITb z&G^4-(d7Tz=1=&)b?$`!Tjx*uzirXf|J#?&_`hxWjQ^XLP5-}c@udGNW_SIc)nEU= zueIcVV@b;Y*;E6!vEl!rEo=TC+qnTePXL;W`~2ZEXx|B`-lJH3URvhv zL;DZ@zj6Qh|GN)CXD+^muho9`^8No8uRv}4Pya#p?tK9583f-w4mqFl`&Z~0mEiFF z^&fObB?$k9o>Tez=kNb83=)UopWlD}|MC6j|L@;^{{Qy%$A8fIlo0yI|F2&_XH`Nl zCTh?m+wA>;%EP_+<*T6>iy^cFW-Ou|H^|GKQ7&We)Ynw=gAa%lr{!1 zgU-C%viGR`mLn$(c7o2lJa8s(^T9LG8~2?^+j;10;m)IHYxbNt-@gCYg$eslUYxQ2 z#JMGVkDXb+=g8?DI}V*Vxbx77lRFQdxVYos@f%zBAG^10-;pO<_8fk^dG~>{8+RSt zwq^f`1-p-*@7{gla_R0fSK{}dyyCI@=q`m#{{U%%>IJbu+Cf4fHb^_1%?Qy8K4X)CAFLO` zW#ykr0kP(Tl(#K{J$2cIL!z#tE@3yJ*?8jbc03=A-KJp%&+=$J^56v$pI zY(^w;W+XQFd{3~q7#MJ|!Ty4(!C*tZ3l@j6!R8RdhMesQv6oD?JjgFlz4l1#dITF1 zM-Vm4;P}GD2I&EvNeZGNaRgCMb2j+QRj6HHHapmzkTXdKip>vk1NcBwdng;4s~8v< zKodpaWXZ_Dz{mg{_UB*(CBacV8UmvsFd71M3xUwkP@c&hox9gATd{NFs#V>q7c7pP zJ8_~G0|Nsm-5fD$(SU_OL2{b!zHK}I-@AGH|BcI6{$DtK=KraqNB7xv9CnVD8k@x8kP=Fw4$v4%i?LQ3bk6Q}=w2JOXr^Y;JS7q9-meDd`F zlLrs~KLDM_b^Y4^OBc@nKXdZr|HFItec!un`}y6Qx6IqTW?jzed5f&3wYLjmHF#8T zNQ6Lfdd`8XS8syP(+2G)1f3J~?K5cn5OfCD=l`JnaPL6(4?lelP7@D7XYzs0&b)N_ z|M@eg|D8B|`0K$vyD#tEv17rGEn9NeuU>7nZSi8zT>EH)c95rl`ucjV`qG+r_wGOW z|MbP%|1Vy>1D~z_>h*{JuitzGpS24*kLDBT3?%4TM_)i^(}2!fdHwGH>t`?jzj*xY z|Kt0Q{@=TG=l}JqSO1?sckchm<0rlyJ$T^a!99EC?%c8^Yu&0&zPya#X#HY`Ydx}8xr;p$M zgU&mA`{v#MH!oiQfBEG3|ECWh{eO7(-v2u{Zi3En_;=>y$uCC_96Y^$$KI*CcI-&p zzHuXHJ?Us0a{yCKR$^M_ilwW;dH?yV_u%^iKr|R5r2|m90G$m4!mnPx{}0;p3&EiM z=pX;Te)swRn-5?9gU);Z_~pm{PoIDM|MK}8`0Tm&Z$A8g^Xl#Ym!R{iA3ynj|K9!o zw?Su4UcC74?5VS_PaHjd;K+dk-G_JW3Ol%QC+IGa0Su9mWp#FP+QLHzj{gV6HzK^y!r4SbWY-H=)C~%LFd^+%ZV>v zzJt@mCs6(I_5*lb@XMz!|37{7^#8*L5B}c<-Pv*Z^53&(&b>T!^3;}NM~>7V*t^$j z*REZlb)QTlD`x29+v3cE8`rMh0pDBq;w9v4Wzc!cGiJ{Gzh%?b|2skVu~(zIf^9`7>wloH~AD z<$(i-ix2MIYqw#;244Dv(D1dTB0F2SwX*T=!-voRKYR7=|Faiw|KEG`{Qu#@$Nu+r zbpGFc;L!g)2M+$QIt?ym0t>(_4hzkb8U|GReW2JdTp{Pe~DXRkr?#jpQAfA`@( z=p1-Z8UU3EptuKN&>a?_x%s#6L1_SVM&HN(pmYEdfA{_~_?*ah;Ckch{|}&a@a4yU zQ2p`o)A#@HKYacF4%7w(x$PO`y#0H3?*G4W?Z*EL=Pvv_b>h^elShuuIlS*+`u0tm zj210gMD=s`hi~jNFk~gCd(E6U>;IFdZ~i}j{r>;6=WqVsdido3k_8L@&z(8<|K5W~ z{_i_*=>OhBhyGWV7XRP7|M36)hYtVWfAHx4#dBwa_n^<6IqU!0m8<@*-?-`jo;`d2 z?>ltl|G5j7z-Qls@0kGIo%0T~J_CZ`aSn}pP&xo%(0v{-{Px2a_}wudL46KT839Tc zpu1#1XSTfg@c-qDH~*hLeewU{!^i*c-MRPw+U2YNE}T98;q>uS$BrF3GGX8DebHOD zZdGGoU|<{0aY%{ZG80moHm}M2KF96Ap=1Ad z>^<;*_3Cy1_iWz{KDQZESG;-q>Ho|3AO64l@cBRJUJ_WD04f*WzW)do1Bt`Zz?=79 z{)5s1hz}|sKp51P`1tYL|4*O3|Nr#q$N!I?zJc#$di(a%e^6cY;`!_Upu2J&-h24} z_U*g>uUx+N@50#&FHRjhwd=&;qb&!w@Alueb}i^W6H0<@*yznkOx<<%%%%S?UcLVh z>hFX4|2J;m{a;;H@qgQ%1ON9NI`)6((G&lho16bnpFHjV{^Mulz-|L%SJ{_ozp z<^TSD`~G*ecKzS6_t^gpTetr|boAu^!$(g3KYaG$|JBP^{=ahh`hW0UWT5usi#Pu_ ztX}zl@1{-v5AWLtUK@Sx)an2C?mhSqy0Zs#kI!pZnE<-82DY{c%!Z@|P|G$3e>aVjW&pbMI>C`zon!Me0Ka3(3u*~U;Kag=<$E>*)7M8 z{XcQ^$p5n^PW(T8>h%9Rckcav{o(Wfx1jZ8@4tc9nY{t6F9X#JptuE{-vz=THmE*; z(x9>eghA;9boUqxgVGGBEduJdz5vx5PhS3i^zh05yLayYzkcn;|MTb1eLs2Z*tO#a z4lUTVd2`O@rAy5yJuh&ur-_W17@h9c?tjmoz4;I7zk%Za{B+pmBr`pZ|l(32;1v z;vQN)fcS(kC>?;(28afYVZC|#?*GeIum3-L@$&!UCr|(1yZ-=uM$yHKm;N0)eB}F~ z-Fr{(*s^WP#+9q%mn~QZ8mrr z!?qp&_a6oA!94wc%G7E9r%jpm|G=?R{|}rv`+xVIz5mxQS@!?v;iLa+Dy#l)+`1Ed zCeI$wIX(M9{e{E-cke$4K96tre$W~JoBtm@aOnS?TetonJ#y^-?YocuzXac@1sW#+ zjVr!`oPYoP<^N}(a^b~`|4&fT#*6=to;>}3{pOwj=g(gHf9BNL|EEu%1>fCq``!ac zyW!)P|F6O60CZ0}XiX~QE;vy86NbTK67N9wok1|D%?YYUKy}AkP?~!837ijJynYK# z509Qc`+xu8qyM+>-TQy-+V%hE&z${x;>fXA2X^n-yJN$aw)HDk1k9N{88j|2B0H4yr5f+<*ALuB`0;_8q(bA3SjQ|IR)8|2H=@{9miczJB-rA?Oaew;%sMd-v)8GY}2B8}0SG z|Ic2&0+$h>v;Zn29)s>je)jzT!>7;wKX~#Ke5c=)8@K+SI1MTzKxyIv_}t)|ckcav z@#fwCm+wFQe*rFgKxqvbL(%{!{-3}30KUuZ2`FuX`b3~Ha8Q5q4QM?)6u*8CP7|Or z(Lw!B(7m3ZcEp*}Xa5~KaOl(CE!$6ST(xTAnk7rZ=X6g2EkPZSJ121^uH@uoq3WWF zpN}8C{Qu_d`~Pp=y#N3B`J4Ys7ccq`y0`PtiPQfNojUh_`I`{D0rc^Z!?G+V=m*@iYG~Ub_1K%H^xz zyE`5{2i?*3>i>ZQhyS0ueEt8^*B}2sfAtQ0=JnCzC%|zFx|iw9rAz-W-njMu{_~gr z@4tBc|NhIj|L?zg_y57`_x~Ti{qX-OC_RAgVgzB({XC%i_FlXK-%$u_S3Z9B;{U^E z&;LJo^6dYEM^FD>x_tfrk)y}|A3uETKj@CFQzuXTzj^ES{}*rGgUcRJ9ssp1K<%LC zZ$AEi3Qhy>|33!V`4V#0J?QM+XP`9j7J4@@=p5d6pm9&ooC)Y|$=BdC{qW(F|Mx)W zQQo}$|HAo8|BoLz{&)9|-4C{H*t~M>vK0jjrq3Smwq<%kg6q_-3IATcc=!MH+jsw8 zy?y^5bO-C?p6>svmaqB0Z{LCc+js8zKcTn#|D0Jf|L+Bj0UbX2f8C~y{}1ij^MCE? zHUDQ$pY?y|!DHb5;L$Uez;|aIICJU$-jnD4Pn|gV|Ctk~{)6(zlc&%AZ{NNXoE9EG zdH(+<=x(iBcft23JbL!(Kj>V!%QtR;^Bic;$)5cO|DU;V5j@8H^wpdHdk-D{f9~St z{|`aw;rXlox4?JcyaAUL;JYe8Wy3p29RiL&&{!e(PQcgyLFEGogYK>bqzi;=x|64X}2DgJ=y#4qebgnH3gW~%sC@sAH@E^nmiNWx5Sh)a83!pj$ zI_?c}1Ne^6mv8?+eg69YqbD!^-@E_lKj&8v{)~{OCxOUkp z(7Do_xbiA3#M7b^Yu7Ga`ybRF0=NA@W!#Hb|Le-j{%_lJ@c+>>7ychPckzEyMdkk` ziZe9q#Y z9lQQtzkTojqZjY~KYj7$|MDd({+~O4`9J8cqh~MQ{NJ>7+y4uful|4Xww2E-u&OWd+&eHJzCE|dHv11|GV}b{D0;8jsKv$ z{t$Fe=d~OE?}EkwU%Ua|DG5pwk3sSF_7iB|(f{WleXrj9fAaG6|EDirg7rNH-OUND zH$ZjA>2sI-i2=#em8F2{tr5X>d=XE|4*L1^nc%p)BmgT3;%E4vFHDh(-;09KY#iE zvbnSWKYRA>ao z&F4;^{eSKDz5kD2f$Evp|F>@0_W$~=yO6tiU%dt20e$uA)&I|5y!a1_n?uKsgYV7& z^#!k9zxn^d_1oaMefad{|GoPU{J-_^>HjCMKZ5RV{J(MQcJRHlPhYiz#muRnmxbx=Bb`uZLC?px4(ub^_}(aX2s_Okq>-T$YrK=!=`-ys0H!|3+Cr}W%g$ySh(`TX9UNAUOuwQu+A+5La^ z)am~>ZQ2YzM|athrQkDuLHCayI&t>@zT-##Z(O+W|C!UL{!i)a`@j9*aqv0KpfiRK zp1u74@agmar_Y%2|H{S7|3T+lKYRJ||AJYwAoneT?h1MI_&=zefAIL}|7+K7{J(PR z?*9ib-~E5^yEq6-u!lz<|K6h~{vSSd_W${7xBt(dIs5;y6UV{j9O#bVE4Oa{zxm+d|3@!hL)r^( zKzAR%2cI<$Do;Rh52Bxd$`)uD1LA}6i?^UVB)>m-MVoU$vE~1a=p^;#%KCrLp1uD6 z=Iw|7uV26a54sb0&GHrhH?H3d4%?GwFZ`b{Y102$(`NkN2Ws2x+Vg+eqIv(%A35@W z&9deHL1&~KJ$ej$w(e2Ty_sh&{XcQ`;{WYixBb8W;K~2TFW-XeygAcn{=aeOF8FTC zSFhjw-?(Yh|C_gNf$t`K^86V%t{yym@c;h(d;f3WfAs(H>v#X}KYsTA*zr^U?}642 zy#>ujJo&$K@4o+!UOfN*{Pny4w;w+Kzirpf|4*NT+WgP{U%GbVKj;qYM=xH3%an^( zZ~VUxYO_6m_y6Q+P#@qTI4+*Ndi#I>p(EhB;{m9Ac>4VRk+bK)cMb16aOD5CeFy(< z-MQ!gidF0W?>c$mgCJ+U%hqX|Gg)V z!S}D;ef0SM&4&;FU%qu4e4pycvuFR`did!7{U|HG$ms<6cqt;8~-6XNGgnf?FuOVF87AHesQfX+v{cJ|!=2I_M?y#Ige=1u=W?djW~ zd&X|x0{6uqJbw27;gcu-&w}ntzIp5a^OtY_-+%D<|BfBI{)5Wgm+wFSzkToF|BV|q z{lEYC$$!xOC7^!PmTg=AKYa2Se1Ge;+mJhN?>%_@|NNz^|L;6{3T}s8x^m; zkN-b<_5T0u`%nJQnl-`oS;&0)Gw1*LbLam*di3!Bg9i`(A3SjI{{v9@`1tXE zP#Xg@J_8zaxqAJ^|0BmvfZO#T{^ct-{_ong7d#gP>W^H$e&heHeS7~uefISK<7ZF* zU%7en|Mfd}{@=ZS@BdBE{dF(i{D1uF?f;Xf&-}l7^ES9Y32LW<&N9Ds@817suR;CI z=l^%^-VI4ppfSWdcm7|yb02)q+u8G%{;yoU_W!nnhyU*Y&1;-E^MCJ&v;X%VKLZ}m z0`+AL|GST$fbV;sw|MFQ)!TOdU%hq5|D|i!{=fO)9ytAj#z7vwc=!6*vv;7e z0c_DkGqKW~g7cToU52dVd<(fx_dRHR&b!axyKli~?t|{ndHwGHyH~IOzkLb1ui*Lr z5AWXp|MdRD|97w7{0E(7{SLI=@70_CTbHf?&-H`$|AYEivnNgg_xC~b^Y7lh|G#wc zlK(fZUH|_aG{*n*>Hm!zH~hbU|Nj4n5AXlKbN~MTlV?D8fWP~H_x8R2SFYXs|K!CR z@Yvj`GiSkapmAN$+CtF%ji9^aUc7>&Gf+I=2Bn7w55RLuHy%O4{KCa6|L;6~3GPo` zyLIRP;Uh=Ecd3K=a+j~&{D0!)ssE2bV~7tP{RiETv~~ZX|2q#I|G)eA>HquAUi`oJ z?8X0kPG9`L_tXXOSjO=Sm;ZOQcmChEd*}aim(GF5m~P#F{Qm^#{^N&_|6hOfbt&p^Z)JZ_u%!rAK!fhp9lBp!)N&2diZFpBU8Ed-&+l|3?oW{l5&lH}K*`@OUq%op1|u$0sN~yng@x z=&=+3uiw27>C?S>_kZ`EegE%1eE9$6+xP!L_v^v)`J*TQuiU)#|Jt3~|3P6r2hiR2 z@817^|Lz?agYrLUE%?*N&;NtgZrr|l^Z%u@=fUFu?>>A3pM!e%;307O0Idr-fAP}) zW5F&e-*B?Ip59+U;zjEpSwY&HKU%q+!fB%Gu{}-=c|9|U|lmE9J zKKB36vE%FN7d+ui-YuCej|(xprO@7lcm|C=`- z{zKybD?51;>k@%$|qzkL4o|Erhp{(l6m)dbzc2D^U^bT`|_&;P$b z@mJ7Y;L!W#KYjfA|1;>0>oJ!EMfWZ$JEh z@%-g~(A}b-d%{8c3632+{2z1|)HBe%v>!kHKYZx$|0~z7{s+$oy?*z9|Nedd@7%ln z|M9~||8L#7`~NJcta$z$yw>N&tvml8JbM8iH#~a$;yZn-8D(f9UA(|93#;{);#NA3lHm@!7LCpnbK}&gUrRT|aV!7qp&b_WTvr z6K5~{-!*y4|K5qy|DQN{=KuMVXa9rNOTB&f;s4wBpmlVw|6jj!{r}Yq*ZyCVvy zb65V~x_%eD?(*XY(B1Knybg*-5C+Bl*NHjw$Kl*?D{)7K3R<8QL za{aphTlXFO4_Y^M?Cjb9*REds|McZ+(7o;d9z1>>ixN>Z;2c`F&i>lPGaqhVJagyj znG?rOpE~*f@bQ!XS8m?-f91yA|F7S?4-W6QpgWadYcoOXzn;DN|NPOj|BvoH`v2h0 zga7dI9-OZ~gUfqZ+=Jp5l)pjv^T#j$KZD8va9o4(JZk)d$_Oz2{Pq8r&!F}H-~WTl z3ebMCPv5|75Fds?_JZ!=dk=CSXdV}IXV$y-;5#;-JbD7|AH4tg`TylhSN?Jx>(T$2lcxMXdSw6q+xI~I&)zOuT*R!v8y$&;P%5`TYNzVEWAe3ujLM-?4ee z{})eR{(t-SBY5oR?K@EWAJpFa^dD50gE4x24~>6N+(YmeM1BU#A>tpD4nX<*3#cCW z2)PUG+vl(ULHO%uP~QLc|1-D@0I@+B#K**+K7IKQ!XH0={tv?+-hcZ4{_ThV@1SkZ zx1fCpFJ3|Vp|9Wlzk2x!xNQwu^L6L$!~e&QpZNapRJ;(748j>n*J zpTkG~-??|^|BahB{~tPf^#8W~hyL#atzElt_5aDsH~t?xaP0q#DU-l!knTQy`v2zr zC;!i!zxe;``E&p8K6>*1=KTl%_Z>R;|MHFN|1aIV{r~jEtN#}+U-^IgfrJ0|oj(8n z=-EsEPo6sUA2bF5>hnK%`u@`O>(@bLGDdt+TVVU@wFmB9z5M^)^-KTnT)XuDE~q~W z!dEZfad-{gp8;;;zXO%aU%+|)!+Qi9UhaST@*k9!zd_>^ zM1KM2YfxN5(g8>wgh6QqBoD%1KB#;^QTq*C9(?|Uh<{l507^#)b3tY!mlL1=fBJ~P zkTxu&e0T-gp9sRQ-u-{_^!b0#T8_8xzkurzQ2p`x-IxDQpTGHk^vLo5PoKR4pB;E$ z|B?SomoNXnZQG9jo3?KMf8*|h|2>VZ|5vP8`TzLYbN{bDe)|9VgD3xY?%DVM{I%=< z?>>DA9%nvy>?pXscm4ML|I1gd{=a7ZhW~3fZ~njcFlhbz#s9Z%-~IpS)!Y9Mp1=Ea z_YvLhrD5K-X6?Is*RTA)cjNN^dpEB9e{kdK|NA$tfbrcMSN`9*arOV58`uBey>;vV z-8*-|Yu-TZ=|`Zw94}t~2ldN9!v70bu7TSjpnU)E#oNDkpT42n*?!5PF)I7FZu@ut z=GFfXZe9KV@aFaZpnGJ%`1Z~J4{qQ1fB)7sFbx*Fb^Sj`ElBMC&1?Vf-2|nJ8~^X# zxeXqZ2aU;s_E>=Wi=cTz(3(lmdO6S%;F-RPqPQc{=BHx4L zKp0&;NDNY6z|ssV4UThY+XIpwzQWrRpgWO2eEJODZ}$Gf$NwKbeEbjUkG^{K=Ksr= zum8Vz`3Ai1@XpQK|1Vy>`TzWt>;E4mUrU$S`N|2Yfh|6jR&{r`nami}M0e#8IGyY~D)aq-H3&{~tn&tLw3 z@ci}vd(Ym|^-R#5*o4qy`}c$6@xkru;COy~=jQ)=cW(aQy=lY$Q^yYf2i-S+?aHP9 z_io?#|KQH8|DZeQAKtz7|IwWr{~z7G`Tx<~8~-2Pf#`jB`}+Tfw?XOU+W!Z4K;pOm zKe~4h-2Zy|^f`E*@8#=v|KGd=-Q)fFKPYX0`uVW*0VxZ<|Nrvw+kZrx091B-|NrF^ zq%DXX=P>qX(4HR@eDU)Ct($lLU%GPh|CviS{vSJb>i^~~+yC!8 za2UKUZq|(1|964*#T`5Kf5p0u{}(P<^ndg2-Tyal-}V2-o%{bEfaV*XzxjXv#k`+UcUJM=Cv#TZ(Y0m|H0kc{~zAH`~T71JO3Zu1I0NM-@Wz! z@!ebhpWFqd6;OJ(`Tr3pjoiKUA9RoH!}|~aKL*XyJbekyU!Zm-XfFonT;2~Kzy1fO zi%;JmG&F8LfyAM41&e>sSrZ@(-qQh6kAy+(LQvd;Fo+G>OA5;8AR5F6l^2kD0uuKS zHl$4hvkNrV0CE>7y}pC)IRVk2^Z;rTzj^omKd77ljZc8qB!l*-+`N77|Lr^X{+~R4 z`v2jRXa65McJlwyB}@Kq-nQfajw8qZU$}AmKWN`9Xdd$6^S7U$Kd1j)S%sbKhQ9)@jf3uS2CXv#trK|$T95wh|D#7w{)5IOL2Hpf z?ZW$@`MhVZ{@;7?_V4{C?~|zAt|!7g*2>)cCl5j44$8M6eCIYee$Jja{D1SZCI9F3 zb^kwcaNqx(>(~5WFsc9l?yZ~upFMKu|B~rb!S{6Cx^n6NiW$@XFP=H&|D9`>|F2oR z;Qz`wGyWgmz4QN>L;L@)nLqdcwvB85Ke%!2|Nd>8!DijLaqa)@o7ex}yKxjb)s2n(b z>iqwW+jsw8wRPA3eWxz|-*x27|CO7z{a>+eEx67zjgo7|7Wk>g4d0L z*8jW!t?79F>i=WV-efTS?*F}~@8*HV-iU}Vsw(kv^pbC_uKWG?E+|ie^60()PwqqT zzMWhDAKbe6|GfU5|2sFX|9|qpzW<>6zCd?p-nw-8|Ke$r|F51m2Yes(syQ?NFP=5^ z|IG{M|8HHj@;~Tar@h;@{J(zj+<(v=Mw?bG`+x7|wf~!!Fa5t};hg`6c5M59^~}lt zYZuJ>zirLR|M#z6`hV=;-v6f$@Be@G!g+A{1FDZ6-@Et!$%Fgb=`H|KGcN7rbWR;gje8LF22HG?J@hhaw0jk%L z>JxDJ0j*O&Weccm2Voc+6z8xy;N^?A|CcXY^?&`g-T${AKJ|ak$&3HD9ysxT%l_m4 zw;wwBf6ws?|F<7G`+xP;o&OiFS^IzWjy?ak?mGltll0*6^Z%gnC(wBrpfw&3U%tP1 z<>gBrszxl4hK2d~`%dZZ{|^r5`}h7oeQ^K(ll%9<^yZbz|DQX0`2YOA-v4VC&;Nh@ z;`#pzCQkUjc;>YKk8a=mziigb|0`!r2gm=$B}@LVm_7af*%Qb9AKbp>|Ek$D{_ohh z_W$jxm;Y~Ay6FGrl}o_&!OnH7|F2&>@Bf}H8~)$Cbm9NX`E&oTSvc?i%?oG#?*`qA zxM=SG4a*n(zjyQM|LyBm{olEM_5agHkAUlyv&Rqrzj5i}|A+T(|9^N7)W!g%(+B?_ z-Mjz)(Y-tWAKtkGX`9}?`Tzc%8{oF;-CH;R-@AS5|GhhR|KGp=06Yf-%6FhWtDrTv zZ$M+2pmRmQ^-E^Wg~$1`hY$Wgdj!Jw{;!xb>;LU57yr-g z@BP1g#+3h$Zr}L7aPq|e3#Lx_|M>O|aC-n0=hrTr`M+b$>i?_e&ia3F@9zH>jvxNN za?Z^E8&@s)|KP^;|LYeo_`h+<{QozvUiyDv%O)^;*QT}qA6&cof9=8r|JN;=_y79Y z)Bg|d-2Q*#;(7l!E?@lr-mUBZL1|_Cs-^$;Z{Pa=;f<^RH?3OofBTx1|BoHm^Z)MU zbN>%+-~9jB!TtZQUpV{!-mRPeZ(g|!rXSqD_x}NCt-$?z;PxmaUEKbEA5=cvzVZLg zt?U19-Mj(Dx9{BffA9W%aJ~E#T$jB44@ws=L2J69YqLS?OkTf-?DYYq2T+*+s{h}; z2lZb*fyYEa>(oGdLoZ*v{QvmT6aNqFJ@kL`#;yNXtl98?-L}2|*KFVSf6BC({~tVh z{2#o=^W{76I_KLDUldV2Qb{l{CMayYB@xA{`rc4I+`xi`_ z{D0x(esKIRpEdLU{K=F4-@9`8|CW`j{;!xd?f==MhyNekvE%>hxikOo*|hQh?aSx? zubegG|GLHV|3A2W^Z&+Wi~et1y5Rry^XL8_*|Y2arX>sh?^w6$|D&5X{%=^a`2U(k z^Z#Eyb?X1IeS7|IS-$B1w$;nQd3Vpowg0!RS_)1Vk8fW8zkS`x|GPJ={eSG>f&aI! zT=>6l^Sb~0HgEWUWY5n3cduRfe_;FO{|9z%2G>)dw&&RsNB&fHb9H|~Jf@Pf+xCokUpzi|Ej|L&=?TS$e z|IeR1`hV%faqw8+xg&@EZ&|kV|K(#x{-4^t>;IC;Q~n>`vGf0#!-xN`m^S7Au61j` z^~B0qv;MCK-K&28!T)s&=l$QfaNhsBH?D!>ZR?T+|4$w{`2WV))BiUwS^R(Ns%79h zd)t~7|2HgI@c-PgqyMj*Jn?_WilzT|ty}&7{+(O@4{h80f5)1Y|Bvk2{{Qj)oBwyM zU;BUe#;I4K+V=n8o~{2+AKL#P)W0~s zXXpPT`*!?4abVB?o0l*CzjXT8|0BD${Xe{K`~Q>24*$P-`NIF>2lxKJcmE-{4RPn* zga7xz>%2dL*NKDnc7XObfyQR;-+%J|4(JS_8@K*nzjpoqjVsswU%h_wdHDa;lSlubKYQ~3-P5Q4Up{;K z|JCzn|6fD#vwQcz{kEs~@Bcr2VBh~EyLSG6{owxp4GS0jUps%!{}=b~{olA~{{M9g z=KjBN>B9d*JGT7ax^&V1!+Uo9zkmHQIFD~#u@v0L+`WGF|IJGm{y%y6;QyN!&i&uM zV(I_gYgd8C7eRMSfzra!-8=t3d2kz?_jhkv_x~hlKL5t$|A)43{(pGKw*P03ANha( z`t|=ucWwKBXwUZl=Z+l)k7XX+z2pDU{X74kJh<=w?Q2*5pF4i||FJzg{~zAB^Z)tN zC;#8Ndh!3!{k#4@c<|`|;|CAH=>RnT4q77&+EW19qx1On$NvvszW@K=#k>CxU%dPO z05nGT^!5Kc4`2KTt>*)c-QBo(`~S6T*ZyC{F zc=7+<^&9`spE&ye{*CMZub)2kf6tmV{|{~3_W#MfTmLsLTKIqS(nbG4eYpLb*Z<$T zY|;Ot2loHJbM^B79V?gp-wSFR+`aSvYSHee4)` z{sEM(j_la}|H8>*{~z4A@&DNF?f;MN-TD90=@b7S+`0)aH;(P!4IZnwd-Ll5v&Rnp zKe2Dm|Ko@D{=ahJ%>NsgFaAHif7ky<44y7^YP37Hy=L#f9w9!|2OYE`VZQt zb?y3%|CcXc{(tGxrT-T$T=;+f{Q3Xq&Yk;z_UyU;r%#{xf9Av)H=0B&k%oqbMy{^P zE&2cC!995Vzj^xf|C^^z{=a_qP4MH~&9=aR2`&w{QO6v3%+Oed|{Le{%QE|8ocT{@=fK!~c^9_x^wJ z;ty+gJX-xOeOS`C^_xEq!{r~Xh-T#ju`t@4~ z{pKxL3?%pd^*hi##NA3p`3O|W9sD)7Ag#%){w?>%(z z|FJV?|6jOv>;KLBkN@9&^8EkZ$It)Y17Yym@yFnGLH8em=%@ehKLYJ9dJf(-+!^1-~DlF>fq}Hzg zub({r|MuyV|De1NF7ux~1?T;@FP{E?b?@f?m$xqefBWFZ|M!n>|9|)J*8i6eZiDmx z``54ke|Ys89QW_uy#9ak_>un^39RV-+uW20kn4O?YsY=HCzb%?msw7tfyjfBN9Q|IeR2|Nk7cU*zdC@LsR&yY_HoLSpZAFzVwUdpta*Kz~>b1*bRyQtvh!A-@0Sh z|1BU4-mARx|E6s_zEfmTp!VUV3zzoMB5sK>(?2MzI3_&i|N6zt zA#wif>Hl}no`LcE=geAhZ~eb?&XoU)W>5LwSY7(Ry1eLrMrtA$r>7_X z@0m5_|IWv^|L;C>@c+I&yZ%q^?fpMv;-vrcW=#3t+tTpAr8xip$9Hf4e}<<4SX#iO zL1hLqhLsiX-n{$&7S#55`TGCs=P&=idHx(cK78}a)&IAzT>k&`-rfJ_Pagk&_SpXa zuU@WWV~(|C_e%_`h+>b}-(sdE0*&UcYJU z|8*O;{9n6a^Z!+A*Z*I(a`pd3OPBv&wqn))t=qQ$KYsYY|C2`#f!Cm3ymayZg$oyN z4aA%eD1G<`g)NJZiu=EJ<7RN1?(I`Z{J($x{QvtG&;P%B`3#KTzkCk9ml{sLe)0eP z%NPIOzlPNLAK$!z#Q&Q&|95R%^S>Z2_D|Zwpf$bVy=Ct{fcJ_Z$^}GPK#qS98p32GrJn{t~=Dd)J_}{z@kp@6<4~lmX2E{!HuUWt8 z|Ejec{;yoK{{Qk-YyYoUz3%^-wQK$#J+SNl(L)EoYfdkL&a1g_>BG}APY2{)q~MUS z>q*gx|BvrE0PgdF+J0|A`TqqZ{y)3~l>yKGzkdaa|Cj$iyawfWNLl~!^_%}7{OJv- zE%)~Sr?(*b&Hr~VUxM3J=Z_rte_+$v|C{E|{J(TU$Nz<04gcEU;O zQpf+Z$M^m}eq`VO6G!&_-?V%*b=^~=})-@JVN|K*EU|4)PVcJDvf4zkKoXziZd7f$pmXWl6eW zH@8rskdW~2nTeVIPaZx4K5quJe(CkgSN}oz;4P?ZfAjkPM{wKz<^T7uUjF~^>ec^` zAhFl4!EyfqT=&2E56b_b_y^U)pWeRv|MBhH{~zAI`~L}4H-q`_{(l1R;d%G}6{rlp ze(nF|qlf>W+P&@nq0MXmA6T>a|E9SU|LuuV1i;B)70-n%g2c6-5_tEqJ_aDFf|LDn^|4*O4{r?iQ z$K%a=NSpob$NwMSeFE?E{P-S}Ki~fU^bQo~2nFu;~A}nT7xN9ys;? z+||4PFW-9b|HeH~ALjZ0+mBxUzx((V7=!M4fAHir=)8&lkDr0|#=rUh~a;?@u2<@%iyTgpag;i?BX*Z%L^z5oB# zJ^TOfK62{+-s9)~?>uz!|Arm={;yoW_5YHU>;5lVzUKeJB`g2WTeS55f+frUFI%;nM#N8#eymuwldhb?Z0&-?(kpf6zHEyAGZBzvl?(jEA%T_Z&O_f7h|||92cY z_kZjDh*ql=6z6qBQP-ZVq|#S|E9Xm|0~vQ`@eqcp8p%S?*rpa zJNEzIy893qZ`*VD|MtB{{%_xV`2WuRNB-{yo!fWh$e{MzkUDd{|8TAfyY8Y^W>m2HJ-oz06s$pM85!?Y4-Nh|CgXMTfy_>uzMXqY2(ZP z576~Dp#2}9{hko~<^SgokTL~1jzMt`!pLIiY*^gGXiyq}Vf1;G@syy^d@?YsVO*>&Lmrkw}=Z`yX?|H7rK z|F7P#<^Rg{Tfpa=tysJ9|MJxv{x4av_W#_4%l=QDHUIyVsk8rY-Msq$i9@^pUpRa6 z|MlzF|6jRw9dxeHT6)I6m6a85U~uSPiHyZ6A6|GPmLlqL=z|9{}<$^QqBo%(<1 z`04*gPo4jN^4z8WXD(d_kDFe(1v-1>F}Un__zZNG4d|S!kN=;8&hiAM5op=~owWyd-6f+us~@8ybd3fM!;+NA?tX*z{(G3+3^v4&IF=gh#vRg{Qnj)mIO)%ptuKN zSQ&8h`mO(K*KPPeYu@7j)2Ge+-``&Ue`i?pp%lh zYyO`&wCn%*)5rhcxN!q=p4qh`qACvlj>h#6`m#p6Mf7!Y%|5vWv z@_+TZZD71+{r3NBHtvAn4Un|4Ve{_)8@KNIziI2v|C={&`M+uH%Kw{JE&acF?Xv${ zH?01@b<>9bJGO59zkA0{@LAt`_8own|9SAp|Gfu~{@-`_#Q*(=PyRo6^z{G3$IpV# zhdO=!>i_eXZ~VV}`!cOL$~^YGdKN6%jWfA;Fb{}-=8YiK_GfAI!{LFX<*$_~(( z&!92{zNYg%bpHrwEhp&g5m0&Y5mIh^g4HW;KY+)QK;ucEehDZYfXV{&_y?tdJGbxu z-@pIB|DAge{a?L$&HovbdjFRc7W^+REc~CEkoZ3#BI18aZ0!Hy{G$Keo$dc;&Y1DP zv$^SiTYKC8zWz!7XU<%a)DSAytG|Cg@X z^ncmv&HtCJ-tvF>nl1mAt=as4#hT6kSA)ul)f@k>TCwW?s>O5vubwyI|BT*-|LwIU z|NC1j|Ig^F`@e8n^ZymIJO8hl*ZY6%g8u)j7f$}acFD~D8&)m&ziI8V|64Y${l9hd z#{WCE@A$uK_ipf=5qm&q#2!5Qe=n#UIdmMHMh+Z3{r@Pq{c+|0xyv{IU%Gzp|J6H> z{@;A??El@Tum3-K`5tm^)0EYjHsP^j^P%+!6B*v=10`Pw{(D z{{@6U{s)~q^8U>`cv}!O?)>ofz5lzmZvDSw`}Y59S1$eE+gkU3*~(S_x9mRnf5(Ai z|2OS9^ndw=?f<7QT={?I>^c7@_IHBQ!MYuL|F7J*0|NeaedZhusfS^esVbTAK zi>m+6nz!=*yv1w(&tC$;3zn|?zi`?5|BIGyfa3N47cO7-f6217|CcUV3BKQH@!aYE zm(1$@KclDqe|mD_|I*@;{~5_C|6@Z!{s(({{P%Nq{2%D%^gqha<9}LI;Q!+E*#GsV z8UK44i~rB)srkQnTFd`cb2|U8ncwq&-NFg~H!Pj@fAfl2|F^AK@PGTpmH&5a-S~gk zj&1+@4kKi_wGORfA0ZE`q+Eu*#CWpPyXKzx+~)Nx&Oz`T>gLh;*I|ouHF5A z_4cFxw;wzOw@n{|&dYK)L%wJ)B( z0=LgVZ~4Du=G6ZSXH5G)ZPMibi$UvK)~*MiZMt#izW)ms%=y1)!Sw&LrcV05 zZqt_k>%nJ!Zu`Gx(^ha>VEyJ@;6B5ObzA-~Tea!`+7-+GpE$VZ|CwX^|KGlG3w#gO z)oVBY-nsKwm0t1h9}v7eJS_HqeQgIg{%6l$^?%NS)&J)#SoMGIqSa8m=Ks7!YyQt) zyz2k_h0FiXo45G?{MmE=FPJgq|NN;v|L0F``(Kim^?&i=rT;IUKlA_c#k2n}UO4mr z?3v^Lj~+evfA`L9|JSTs`hV8+DgQfLoBr37mHf|3Pye479r-`h*ZY5ftMmUrS4bMk zhzkB+mJ$2Eu{8aEZ)4H_nSHhY7td_}zji_2|4mCL|KGHH+W##p=ltKkX3_uc>zDuE zvT@D-Et@y~-@bjv|DC(`{@=a#;Qw9w4*%b=@5uk1`;YzKeegK=PN_pD&i+4k`qKZ? z7q0!kaP`*z%eU_Tzj6QZ|2t1!{C@~KQ~c!z@cDkAvgF~55C0#({P6$T%MalDpg?^A zP+t&)Up{~JA2dJo;K|;v;Qw!vgrS+ zl`H2^?|1(GTf%m@Lym9OQwQD#3 z-@kp|fnM<+5E#5WJUs4yd;8@7(`GIGKV#1F|1;*U_&;Ob^8YjEE&o4j{)+#zL3rM> z|FdQ<{6A~voc}YXP5VD%a{vEX6FdIT>Tmr&rK92h)CrURuUWDB|I>#L{y%^G2!cWD z#zE^v?%(>Mp8tRD?CJj}jvxKMZ~yN9n>MZk z=ONH};f*!5|BG|7{-;Do{EzVS`5)}&{6Eyg<$r8|*Z<6zkpE@b@&8*Zv;I$NE&V@l zQse(+vpW8-n&0z(&B6))*DRU>sb^L${J&xC^8Xt*toy%t%a;FJx9gbCjT30T`00~p{~teo20nB0(c{P9bAc{gIRF3H;Y0uT?b`8w>&A8e*DPD| zf61I#|3ULw^JdQYzi{@X|0nlt0muK%>sP^dR9?G&>;JtQ_h^2;3oLyF1_qyxi%$99 z-8cLH4JNv&RqrKY4f$oJJnry9HjG13Fva259}<#S8y0oICaZ^ob+?5A5IlfAgkw z{};`l_kUt<&;N$%s{e&q8UK@`BmYMS`2G)ecljUT?fySG%^}T|>psvKo+tnB2h}s@uKquB<@Wzew;qDWK<Xbmvv?$M{u!21Y5>&PBFc=-Q5Xiee0`~Pp;yam2zvu|F@k47mASmo{N=n}Uo{97S_fK2+f8w--|0mB__f~wvr%agee{yg4|7qRr|EG1g{GZa<_y$|5=K5+Z{-FxtSA$ZOhv~J+lEAUy7Z(qCs zuP=S^^vVBck01Si^6q{J(7dmj5d^ZvVe} z^REAEw(kDFdh720Ye8crpfM8g`HyG+9|WCaeEH`8b2sk)zjp80|2vOf{Rge@zV{S# zwm4`!{n>xezK{F&AN;>_>-PUEm#_T4e*ek;s}G+2zwzM3qx<)tYS22~q2_Z22Zg`O z&9C_1KY8B&2~+3)pD=YU1W%s*f5N00|0hkH`hW6-N&hGJ_x+#T)A4_5ck}-#UCrRQ z2giR$?f>qky8j!Nul#@Vz(H`lfB*F5|BugK@#61DXTN*{o#OyK3l21n1H!O*0nog` z$G4F6V((wS{r~+b)Dcklea zf9ux&Ti37szYZ-!&Yl6CxqA5ju3g*yuU@h2|I~>S|2Nju{LjzI_@59N{y*5;^S{5V z^ZyV}xBqdWe*g25BL7$CC;xA+$^YNmRQ7*Td*%PBUDf|*_BQ;VHL2tO?CBH1=Xoqx zxcL8~9|FR9+|F7J%>;J0Fd;YK9viJYG?Fas^-+l1^)`Q3Y z?>cto|NhgL{vQRc{knet|K&SR{$INNHR;Uv;BX6Tl4=3ZH@mY zwKx8s*jD#{LTl~+3C&gi``TLnuUoqG|D}^B;qebi17H4s|NI3!KLnb42aUgg#`(X3 z$_HrtfBpRRKL~@=ef#tUTvmW+kbV#bl_j8Y9T*0s4Uici3?Acq2U`DwNFSiJrf)&> zH{kg@$U3g4Pagk&^626JM-T4(e{k>4f6%!kpz`D9HPHI(^Z(DEJM;hK$z%Ty9N7DR z!-jSL=ggk@zoWJJe_2t{|K!BP|Di!a|GnMa{<}Ln{15PU`yUq`@INOd@_$uf^8fa_ z{QvzO)&HmUHvXSB5i~9|;s4x43;r)%zvch3jXVA?+qnJz@=YLm=l`V}cYyJd4cq=N zS-0v|Dp{$A8$Kw&TIevD|FrS>FevO7#8}|6M&(|9AFG z`rp|-;eTgW|NpMe-v8Ylo&USr+Wz;pHi6gT^fuT3?`^LA-`8C8zpuIKe|t^I|B1c5 z|5q$p`2WVmOaH%r`uZOfZ(#iS%l{Y8pM&>8fX2};oWJn@{J9JNL2S^uYgeya`+o~m z-`&3ZA9P3elZQ|KKY#M#|EuS({)5I|Kx_WMX$CZJ1T7z6=>VAqrwJVMLLWfqh=R_T zee)K4t}JLy`_+q=;JN1)PoMsO_862l9{qpx;68W{80dbvTi37uzkd1h|H~K7|37#7 z)c+GlkN!Wff8YO28#nx4FmKNPj<(kS#YKhxlj0NphXe)v_wo1n9~kKWKPfThe^Ev0 z|MqFK|4&%D{{P&yTmLUv4~pyU|Cg-a{(tehZT}ao-THsw+AaU*t=as4_Nq<)X0P11 zZT7M~;tT@-g8hO`Vq=p2x3o_9-_bSse_O}I|7{(8|J&Pp|97-?|L=l&Sxh&7J%I;jP=?{0okIa9;lM zA9Oy{?HgDB-?)DD|J7?({$IU%1-#zj+T|;JD`yY>GT=+2*e5B`JpRz7?B;{WRxpmpVtwE>`W=U{08R5pOv z$TTP|!7ymN4}?MEJ#SyX0k8J}_3vIifARmtvuFRGJ$dr~$)iXAA3uEX|G~X`;4%ZW z5Aep-%m1%jyzu}0+0*||ojCsg@Sy|$ckS8%Ue7ao-kkq^GiLp7oxb3I_2dQrtEVph zKWE*h{|nY_{y%^1=Ku58Z2muQ)u#V*S8e=1YsJPNGnQ`xwetpKuMa4>g$9Otq^0Kk zZ*J*>$9sEQ_y6|R&j0PrZU5UEoBp>q)cx;lsQKT~Q2oE7z7pKl>#Q&P-&tS&zq7vd ze??*L|LN0b{a-qJ?*BKBpZ@>$@e4fvfBEq7|Mklk|6jdy{{MxG7r|{_&|2q<=gHp=cm;YbBav3})4muYVbk-*5KJYW=FaAGy z_Tv8&XD<9dcIw>!<0sGkKXLNh|C6UdY39=Z3!uBguHO8A^VYrp_wPUa|K#!0|DZ7( z(Aqyxe8b`&lrCTxCI+HGYCss2Eyq+DjF8uMMN8mFd@7)8P<#HRm zZ}`SlP#V4T|NQy0|4*Gf{{QHaga7BP-1vX$^7a4ctlsc{?&^*I=d9ZBf7Xf(|EDio ze|y^EwHBZ_7)Trz7#5wETl~Mdx%+=xbNBz&=Fb0Z%^m++8(aUkHZ=Zkt*iUrR#)}E zy{_VaTP+Be|8K7?``=bu^1lU27v|^xpFMr{{}prR{r~Xt^?y*^4Z@)E8C2(AyLjgR z#S0g~=cS%LckchmGiU#wI(6p%iIb=QA3bsM|Iy>8{vSDZ>i^+mpm~7P|BswF{r}j> zGyhMVI{W|B>2v?joH_sh>{-x08A#m$G7Gd``qIUV|3PaeFI~C_-dA<;5~K_{d;a48 z)1dSLIzRE`x&KE`oc({~*l92Zu}^`@lS|kBU%!6q|J}O}{y%>7?EmxUpmVB0XOV-> zoW?$11WFGe3`!HAx(SpfK;^|t&|2}QPyauC{N(>5(ET*`@BhDh_bzz9=$VU`{?A;x z`v07j8~@Km>iHn6hlK-t$h5wtYivKrO7XB~DFZ{o7=A8d) z7cBh$<=uO5-iP(~KOWs-S>a(nvMTAY~1jF)0Qp&w`||`f9KAf|99@%^?&E? zegAjuJ@|jmp+n$%K@ULBMLK%w?Egb2&;37e^6dYEC(isoc=F8uLm>M2ss9I$p9ZrJ zf##i0oc(|N&Niy#D{@)!YB?-n@tG zMF8zv0j(PW%@w?P{~uJgym|HJ|EpK8{=aOW}RFzBv{hmW8ApSxuB|7lCs{GYmH z&8O)L)~3V4elXC{;nB_I74`qCYg_););9gGt!emQUsDUdm#e9|@_$2R+5d*h(*O09 z#s3>BOa3=imi})lF9zfKilYDJ1zG<~%WD45pE2wImK7`ifBo?B|MyRy;rR8_r~j{9 zIQ_q&H0OUtq|g7H7@z-nu|EHcV!Z$7#(MtGi}C!Q7w!2!H_GdOZluru+-U#*d9gwN zi<2Y&mu1BLugXpR-&B_WzpK9L|Ada#|5GMS_&;a%oc~LfEc?G^{igq0cklnd=kUq@ z2abX6lmy{3{|_DqrI)k+L22XAv9sX0#lt7gfXkKRCr*RUu7=$8diMXhv!HZx{{Pu? zpt|GY|5Inq|37)={Qu*p&;LJi;tcp4r$a{}Wz(^f=l-8Qd+Gnh%h$pC_V3+$^#2Ly zuBjKGcz*{z3;hjf?*ZrxxL2?LKYs;E2XFq*T(suj#04uZO`f+(cQC{`vKtcPQm0o` zHT*BHtovVCQT@NFqVj)jMaBO*P`p=^{;w}Df#Rb7b>)Ts>&puM*Oh{B-v8Rtoc}o) zN&jo>oBuDIG2{Qicn+|DHp~|L;8nnjbjvfB%u={|_GptvNmkKJ)kF z$y1O$nP<-ZKYQlF|1;+<{y%;0BKSP-Q)eOUQ)kbE?}h^14|VqZ<^Q02=wH1Cojvsi zd>{DJ=WqYcU9@h-qD70ik;8qkurt$h)|6G${4Xi5{9jg9{=cHU?0;2RDR_RSrmXmX zOS^a`v0$)!gB z^LwrS$K{#+&+4-HUohSJe^Q<4|DA{)dH`{P%Y;`5)kH_TSIR=)bSC z*?(V0lmEVshX4H>4F3B&82|ToH2xppX!<|M+3bIatM&hw0I&bK$?^Z|D$D=(_4NFo zzhDt~-NLRz$Nuj=d;**XKy!(pwQis}f$gCAqrHdz@7j0d|DOFv{_j0-;>-~c>C(z|JN@;=Yzg^%fP@e zXzzM2$S*liT3YeHtgP&RS!wD2ijw006~%@BD~j^}R~6;|uP)95V^F+7caPOY~ySHuofAq+a|3{A;{eR@}k^hGd z90c!GIlOoO|20b&f%gr+di553x6$htZ{7^%_%AFhzfxRW{=cNS_x{NLBn=)aGn2?RTv{PzZ@1M~mhju!tt?9Kms z*qi#M5&Pnk6R|CUWV{;yrOWL*8h9AtoeUn*Y^MWcJKMWWX??RnYQ3M;N|Q8uU@=)&A`CGK3K|o zbaxaMmEA8YF8`ljQ24(fFaLi*Ztnl0yxjlAx!M1VaVQw+^WFAs zTlYW2#pHj8v*G`g0+atGlZ^l8Pd5G^pJ(zv)WiILY_!?`kYJ<#aY^R?W0H*jCzhE1 z&nUC`ALwKFKQ>+efAJi<|D{VT{%3ZZ{Lk&S_#c~P_&>SE{C`}Y;s1ajga6^7`u~Fh z4gUu@g31CzaGl@>VuRxzk`6#=!Q0XJzn7!Qe=kR~|6Y#f|J@x-|GV27|97)7`tNFM z^xxIS=)aq->3?@Si~n9u*8e>nE&qGjnf=d*3Hd*>zwQ5w{?7khxhLX z$M=ra3;)mRZ~s4I%9Q`RckTYaaORZ%j~+h!4~zddgFOE8iYrVDib_gy^76a$a`G1C z=H%?i$;vvHo1OVEH!J;JUS`U#g6#DFMLB8zi*wWd7w4q@FUd*%Uz8dDKRzb>e|B!k z|H-|5|L0EV|Nr{oLvY@Q$N%R~|8HEm@PFfqdH*BbP5wu?8U0T!Hu+yP+2nu0WRw5d z&F253{4D>6dm8_b39 zKcU>>e@wc`|I|{;|Ix`N|AS);{>N7t{EsU&{_p2v_&>nO=)b=cC=D1x%6(`#;NxKY z-^;-W9RHpUrvE)1&HuaEnf!ML$GgFQXB&h6&Q=Eh9WC_!JDBT$v6Gele_Io+|3Myh z|EKme{-4&@_J7}=o&UFQ-3%`8cW>YEzcx4Xe~7ySc)n=P%$fh^PMh%m5$N0`XdmF! zi`RoX|D%@&NPH$&S6A+|v^0^FlvuT#^knP&oV0-a^pw=%?DWdQtmNM4=*V4JxuyT7 zg4)`XCjS5Y^5y@ZUl95K+ozADT_89)pX|(wt z7GUx}#KY)+PP5tnj5>?|VP3}nV*+gchx!`*&uy{#pImS9KQ`9le_X81|D*!*{|QCL z|Klrc{ulP!{15Tb{~r@?`ah}6z#VDjI?&iKE(ozZ`HJH!8Owg&%Qk>cOZRQo>&JDBVKw=>cD@9k** ze_Bt||0zAK|3PON?%cZd|Iz&i{~z4F>wkVsIXZ>HV*mXZJs~+VFpr zx7q)AfBXO8US|I@N^SpVb({Q8O0xK$6mR=KwZi6qe3|k8v}()$71JF52l*KM&#W{5 zpHOW0Keylbe|WUf|1dYR|Dmp?|ASmi|NFZ_;@{8F=)WH*4LE_y0K@;D_C{drVQ2W? z!^YshyN$trS8Id+F3|iBihCPlt^W?@djIW=wf}qA8vUQ%+x&lOPxJqS`}X_?#s9Ix zhyNcubm0HO*|YxVCCB|Q&&~S3YwPC!3#Ly5=l?ga-~N9E+H3ym?W@6D|6`9?;zT1O z6Z-RVivG`?GUfl8d2|2&{P+=E{)5T@&|EHPe=z8*ujyU&|6@VzdrzbPgMI?Mk_1t$M<+D!jPM49}L@G$!y=57uiCkS>m z{U7K8>KhpU4{!#x1&zV^-`n2!KL~@;frq`(e>YGWU;~MNCkws*_GUW&ZB4ZQ+neeB zw>Q!G?_#d|e;IlDYyR)vzWx7!UAzA;nlTwX z&;0t$Tkv@|Z-;UGN5mv<$j>kSzhLU*|67+X{r~IJXK>#C`2{le13DWFbZ69r#?t@s z9%lceeN6sWOtAc4I@RQVN|C|;I4`sR3BDHpW5P}Tmrk<&pImD4Kib#oe?qX`|41*> z{~1N*|4SxX|Bnnc{-2y}_CKq};(vCt&Hs!_tN#U^*8jtO4gV+SnE%hJGX0;~V(>pY z+~j|hJEZ>@>TdQw*wy@h5EO&bfj_t(2&xM}>A?8EhXbVicegY6?+&g54F5Y@>i>5z z)A?_2s`KC8T<^c5neKlFW6l3F`r7_a>1zCc_y8#WxBfqN;2@+dShw{5%9;KD7tfvj zfB&vs|Ch{|2%a;1{~B~J5@=5G-LTF75itqJOH0bZ@xOP&dT`tSJE;8s3Tpd*2A?4S zivRY?oc{@4X8&XS4F8u-u=-y%$?Sh(it+y>U(5eVewP0eBdq>s)|vhM>DP{;!;9`@f*o?0-^}!T;1itN&^K z*8fxet^Oy1aG>@7tYYi`MV*fS^IL8IC#6{b&&sg>9~W%cbN`rp&R$;R}*gN6QoJAKvv zvnRCvpVZm%|ImSb|95TQ_W$641OE^2-t#{#G~|DXtIhw5$M^o9)zkie(bT^GpmpIN zKzE0M>VTJThHL(3jE+lw-BRE1fBvKi|1TUo0PgpL>V8=KgU*cy<^S^Zu>XnP=Km8z zO#W9*b^4#xsQoRNR$8RK@R`(a_s)+)|mg#$g=&P9_REwEy@0WZl(SIuHPph!~U)JaGKd;gDe?gns|AZjR|2d`h|1)b%{+CU)_#YKv3Z6HJ z_6DT^%l{D`mjA=O5b+=E2I?Px+JzSX{oJhn`?}iv_jR@X@9S#!-`maZzqh;He;+r8 z|K2Y4|2>>-{(Cst{CBj_|8J|O@_%Mu%m2w;E&mT6*#Cdmwr&4G_5ZO$hyTx+JQ+Oi z&|6dbfBVMO{}<1g`2XqCC*b@KZUel0^MZkafsMEp)zDED9UaXV9hds0tGW6A{D~9( zUq5mD|F6%Gwm&HTL303)?%w%-gRrQ+&+-r$<`+FYB}YUq9dae@30*|H3kx z|Jk8-|BDNp{^vJY{x8UL`kx-={696w?tezI-T$ms^Z#YNHvi)SZT_bw*#FO}xBFi? z%l&^&y*;?ypBQ5MKeNE$e{PHQ|AKz2|IwjV|Kt7b{>S>+{*U&t`5*0V^FPYV{C|X( z#s5%GtN)>%ps_uh{{ilH{{y`o|A+WE{}1tV`yc4*`rp^f`M-~c-G5(C`~N=PF8@7T z9savJTK#vjH280;ul#=|sQ&M1{eKvg|3Uq~Lx=w#J96~@(Sry7AK0<^|AF1R{~y@3 z^Z$}rQ~y5$otp%j2L$K;x6g)S{Kv+o$;HK||L$vR`#*2ug#ULhod5sx%U5U_02%}S z1U_Hy`o%N<^P=7Ur}9qbI8)o@GF3|RWoWJe=I6pfuj`ef=AL;AxKitpZf4Hy1|6q6P|AFpS{{!8u z{`KV)!6Ub#{X9e0qB8Cb<3g8`S>$0*U_zH?RG_a_;2+{Al<8SwXh{ z^HXg8S9F;FubpE1zp&Kee|>}d|C&md{}p8p|2yZn|IY`-WrXAZf+)xTS&=sXD|%f2 zXO>z1PYAO8pPTOXKPBJtf8|7v|Jikp|8vT1|0f1J{Libf`Crgx{l9pE4asm_X?|E_kH|6Q$&{yP||{-4&>_H*KZy&FfgzX7pg-?Rd{%`TS{8i z|LHxw{})Y}1RnbZmHVKvUl9G{^QZryyF)LWJo-N`(&c|%nB)J-Lg)YG{pSDc`tAPb z$J_reiF5m366gBAyvq51^IX^e`B_f?i()maLOuS6dfEODaku&(1S$hOZ2$YaS^xKQw)h|5X7k_I#p=J0i^YE* z7qkD~u6F-j?JfVi+8F``O$4w>2~V z?`m)Ue_DUf{{_<~Amab+oBwZKy}LJ1XSvfdHHCylMyF@y{-4#?|9{D}DgQq{d;b5| z*DqiUivRDQKK{RR_0s>7hxYx?jd1>-7w-7KvfTB5RgdNW(mZEy+?U3K;@{-xW_+v9&;iR1sY zF#G?xd3OJEt1bVRG}-@;3$^>76a>lpptz3>bo`$Z?e{+=#{YkEl<)t<2=D)~A@2Vp z{T%-Xd)b2P0e@GE|9-9(|9wF;s6KGD`tJprGj_B8?`&)S-_6$KzoW7G|EWFo|7TC` z`41ZR+q-@1|09PF|3AF%!2hDO`9aUub46Y|Ccv!|Ns2@4cz|&^#Q+q{P6$&m5cum?cMUf zAj%nxtE%1pw@i2aU)g5=zckYo9M8pZuK#Nrod4HPbNOGG?Eb$v-s68on&GwY&!smauztjIvAE*ERZlHAl zAZ-0Vz}*UrLGkbB;q>3l-W)tX2#Wt{-Sz+HPMrXb_dPqd{Xco^`2XWakAdd_*DhQ9 zf9H-Z|MzX*{(tGb8UI1|Jc8o?9q4}Xm+!9+MEua&&WMP(mZJP3@Vbw+b7uel{_ey7 zpI^WJ{|!w8U*Es`fA8{z|9iHq{$CjF{J$jD^?yyB`~TLd?*FSh?EjZ#y8H*_|Kd28 z|8<>C|Lc0){ujqX;=jJ!_kZj3!2dN}zW*yLLjM;f2mY^a2>RbJA@F~3i}(MkUZ4L3 z`7ZxcBkledmAm~f>9_x1*kboTDa`4AQmD)S1Vx-Ui2!H4QVSdj413Ya12e^ak0h|AU9@hVZJgxtGJ6VAD_;@(k{&%-C`|oI? z`G0zM!~glyC;dNq_|X5|+qV8cb?n6dlgCf|KYA3j{$oFQK5+l`ZU0v+oc;gB%a{K@ zyaufkefR&(>yH;{9Tx*(et2Zu^wQ$8|BI$g{l9t9!vDWMe)|9G>o;)x|Nipz|Ce`f z{@=fH;s3TZ3;!3zIR6Lb^STC5{&)Xh)nxs@B+(fh|0VG*|63<`{;%qE`d=LH_P;33 z{eM}K>;Ja?kpDIP-v4WAga4PL1plvZ4F2EH6Y{^j-RpnD3^`d-Twf0P~NxsAM9oKKiJFWzqhO9e@|!g|DH}(|Gn%j{yQ0K{-4#`^ndZ}so?(J z?rq!upE-Ww|EUuv{_nkT`v3IX$NwKZu=oGr?c4sZSvn8A{ug|H`MY=j-@N^FY9Qi= z)^4sHX0(m~54kN@SZ_Tab&#eYen+yCa?;QwV^UjJ)qL;jbfh5oN?4*TCS zJ@|iBSK$BVIU)ZG3xob=r~3b|Xbk*cH{0`nQKS3+tZ4WDX^|fP(;_|pXTgW~fuxwg{|TV@5BK>W8R+sq#K-P`keAK>01r_7JN^&$as2P^<@n#% z!|A`5tHXaU2h0Dirdt1JO=$VQeBR9ehYuh6zi0an@VVWf{12)JKw^jX@BhDl`{w@} zRxJGg8gw4&8_1r-*Y7?Yp>Ss{b#WHU0m-b!+~E@;og6gX;f}uV4Ou zaP{K<6?6K*`MfN_^?ysB&;N$Wp8wmXyZx`Jae#=YIsI>(==#65!v&oGL3KcBvfKZb z8Dak$=J@=tuM7TPmKOTIz9Z~^`|R-ll^uTn+vY|6&(90|Uyv32zob6+f5V)x|M_)+ z|8tWg{%0kJ{?AGb`Ja&(_CGx#?0-f)2#5Yp1EqnOp#O=W_>T_w9~lSeQ|M~VET>gXN|HF%C{~unz_=RVrojJgbEE#}X9xT*Er|MGQXllceqPA`;+l~Exv63QbCSdVXD5gK&rS;c zp8>|<|I-u0{-?!<{ZEMt`JWgQ{69V_@PBNC|Nq!<-~Z7e-v1+lJpP9Vdj1df_xK;; z=l(y)$MwHIDF3_Ig4+Tf=34*fPwn`>e%XTmhYuhAzjx=3|7VV${D1bu$^WO1o%nz3 z@KJF5@7=oT|F*Tu|GxvDbqtFC_y6C#d%vBQ@i0JUGbP5Q-tTN~{=a;}g> zDE>hhR1Um*`sDwEYZv~{>8%5o^F@hH|GVdT|8Jk-{l90n^Z&*fmj7F7UH&(hc>Hgl z;rhROnmsuFLG6UfOppKVGXwv(&k6ZoUm5bhAur^AV|(!b?zvI_D;om;cQ1_nUyvR6 zzp^a$e?h(P|Hk>D|4VBk{^zEK|IbN|gv5Vx7&!hxaSz4`;r~4l3x^K<2gUo}??1rwudiSKzXsi%bp68rsjbD}{9h2~{J(XA z$N&01*Z*x3z5aJh^#0#F)%Sl(MZo`=3#0#cP4NTQ2cR*bs$9?iZF2(ucgzm?UtJXN zzd9%Ee|<;j|E>j5|EoFz|98%d{9l+I{=cRs?te*Z;Qy9IA^*#2Bmd{8Mg7lBiTW14q=^3+i4p(P6T-n|Kx$mb|Kyn9{|S+x_z(CW8Rq*xGQ|6TWQf=Q z$Y9U^v624&BKfp%k|Du`Q|F^7O`X99J_u!u0|4$zW-BoZB z+z$lh|6`!?fAfa_yEd)<{~mm{_2>Vf^Q_;z{#+$SX1crzj;y6|MmqT|0@gp|5xM&|F7)|`af|+?El*C z;QuYN!~d6n;=eZfe?@!X|K|Cj|MQDO{^zAf{LcZWfr$UvDUtuP;PDTt1H%8OC4@ry z1F=E>6QTqD$3*!3j}G(sA06ri#*txO|Kp?m|0l%;{%@_z{@+-Y`9Cq->wmC=!T%*Q zd;V`*x8ncdg9rZ~+PmlfDNy_$gT(*QLr4A}-GAW!?hWhy@7b~z9RHv*%t7)0_U)&6 z0})5Gv@;JUg?*GeXO#XlO!iE2^xCg~QsQiER@b3S6*Dn0;DoX^%e|ehc z|DIX?|Jyo3|2O4_{cp?({a>FI{J*_A=KtjR$^V<1f}r`|^?yUP@Biwl-v2wMhW)R} z3jSYR5ca>OBk+IM;_(0VJz@WAdqe)0WJdfitBd?!)e-f-X@2DY-0ZObd1(>AKKLt_-WF&?E2VqeBr^W~WPl^lvA0Hj~KPJ-ue{{It|ELh}|Iwj7|D(cu{>OsG zh+>2O7v?4YuP)2}pB(P{Kh(wI|FRjq|F>^g_5aZR1OE?$?hAv)|M6qT{)6Hll>c|F zU-N(ewvFI(>Ot}U>D`C_@85r%O3Szy2(we-Q;aiHbNxyn1lw|Glf{|F;)L|1XJm|6iT!`+xG>u>X^1MgQ+^O#I)HAN9XEKjQy{*3|zK z7smc?Y4ZDDmI&z+mL|FW@17O$ziDFN|Juxu|25?i|ErpV{`bs_`Cr{0_P@Ft6#tR` z%WK2`*G&xn-!Lcie_l@b|J?Mb|GBBr;Ibba|EW>`vr;0!^*}~a#Q(H}u>UFXA^($N zga0SR1cBo^D#G`FWT-bd4S?!`IM7&8e8~UO;`IMDRR#ZJ0$joK$jhep{NJ^C?f-*& z_x(S7@WB7mCqQRSo&10N=uvR|gYrM-+cr|NZd`g1`Uz|LfaV@Evh?ub%neoD=%LEWzV{LrKv8 z2{R)9&sduHzrQE-e`jgx|JI_o|5N)?|Ib*G^uNA1;D2d?JGcxeOK|_+)gJY~u`BR@ zbynE_`udpv)y={G+vkM-Z|y|BAY>|Bch5{@B~S=RsBnxg-azE1y>gIxYEo!0$-@Ai%V5A4|k9s>l&|FM(*PaK8h|0DYk z{NKKI)&HaWw*Lp+XYd7dPX*{M@DHErX&Dy-VRlMVN_0+U&i{qerv6_!bL#&OPoMq& z^Yb?t|Nimo|L^bL{y)ESV9_4*%aaA@qNJcG&;=nyCNveIft57Ki+= zpAq`MrX})!epbZ)y55-ob+bbM*G>!npOX>sKR+!Jn*TxZAN4;oH42*d!~bU_hk^Tn zso*w1$bZl{P+U~N|EMtE|Ittk>Jx(EKRqSte`Q6^|AyM4|KXlC|Fgoq{x6=^@qgdW zt^fD$-t+(Xk;CBn{{*P*fAr}8;|GuYKYHN6|7~kmfX{OM@a`kz{*w0}|G$3wzGNWc zh?aIHC8Xx(W##=}GIRR>RWqmk|MKcJIPO7d02Kd!etiG`?AEpa4=x}3UzO|)&eJXB z{{Lq#iuu2EUHbneb1VN(Z7%-bU6KBO_VkSZ3zw(;ug`_VKd269?DG8IvpDj9dw1CX znvBr@ZEdmt+h>OVuk8-}-!LWke@$)V|KiN>{|z0{|LbOi{jcr`0+;=u_CE-N&gIHV ziTs}d!r;6Q%m0!8Q{p53C&z{SPlyTp9|x-c!Sz0<9Ps@g6BY13F)sLjRz}?as>+=I zwUzn*!`v+Y=fwp4Uo@@j|G_;w{~z4F`~Rt<$NsNbedhn%xx4u+`heSiwb}0fJ8A>}Pi#y0Kcy}Ee_vJR|Muee|6L7{|0ni_ z|F25(`d=Ck8vA$q-!milf7hI_|7|T1|7)@%|F?ET{%xBQ^{28u#cO9k}-qaf{nP#*w_L483`9grFi8V7*pe^4I~)c*sG z1BLtjPmBuqpAsAVzo;PPe|1&P|B90A|Dmpy|I3m>{x6x<@&CyFJ^%NE?h`!*iT{pi zTmH{lTK0d_xuL|M>st`sM#OPwxI-lj05O*TuVm%lF#Mp#M#Ik^dWW zBmUQCh5WBh^Z#F-5q=>Mg&C&BIiFQEI1-hcZ4 z?%n5TTE@jdn4O%Ex~#gm?EjkiGym^gG9NtW|M%CQ|1kXf$B+MyubusWV%zfn6$u{T z{12Mz1&!^1+ID4$9{2P8#++kfea;r~Y+)Hc=-R8o%_K1K{hR! z_aAiD)#nc%|AX$C0Nq*j_0!j&fruko+L@A=y1k*I^8dPpv;OZ{x%B_9Z{Oi@|L4~q zaQpA}iJkvB6 zCrA9xO^W!Rof!T zln#9V$42=6&q$5e|CJ}{}4Of|6LVn|CdZ@`+w%x5%8XmGpA1e-?eMc z|M?4-{-3*W$^RwGR{lS{Z~y-_3+Md5b@k$ZSp0*|BK-34izhAPVj#>;O-wruIu~yJ zqFMhBtXuW}&ySyo`2YFm|L>na{~zD7>i>zgGygA{((r$Nf6f1S-If36b(a61-&OH{ zXZxiRPe#M+F%edWo2JBt(kHD-tZ zD^CviT^jHEyD-ZAUv8-L|I8q#|LH-_|I|brsqF8!B`DCkH$I54F_z-(QpUf7!J5|L0B|`@e73&i`jlo%(<5`0@XH4}$JJ zI`DtX_U+*Ef9--<|L@(r3Xgx#U6r5TzjqvnIHIMUX-VnVyPKN-uU#Dj*nx+4@PV4!U7KR4d*e|m(+|HJ^t{}CQm{{x*&{|7jk{tt4s0PhhB_p<#T;qUlAF3j_P zVRqdA>XNkok?yAd11wek&uq>Azj8Vx{txcj`TzXsv;WVYIs+a90<8f%a`4dq69@MH zUo&s!|A%*Of$ydSmH(i7ia&h#K=->mX&Lt*volgMo=#}*_`iDI^#7-KZvFq~*Kc_I z|NH&-|DWHWw!rWIe}Dh}|NGa^|G$3x{QvX&xBuThzyJU7)#Lxq?_B+V`^?e*=k{#= ze`MW~|2r4X_`hZ5g#YU&cm7}1-}--fcf;=)w|6ka>{QtS#%l@C;x$OVx9n1co*uM1t(d|qA zAK9|_|G~|R{_owm;Q!8bbN+8zJ>&nzWmEsJTG0Q0!PM6OQ@gAFcQ+RPZz|9DUtO5| zzc@Sge_>Ya|KhyF|1o~{|KokF|1a#T`oD5U+keo#@rQP7{D0xp>Hp_IXM=&(0D$gv zKXCB>u{}Hfubw;U|I-KeAn^~nTj>^6CGV zkL~+^V#mh+2i7k8zjN{2|C{Gb{l9Kn-~ZK)~>umVH zqPO|~s)_CY*G=#Fzj^MY|JxT$|G#_rtp9sg&;Gw>&7A+c*Ub69Yt`)kTUSm0zj4W= z{~H!g_`iB?*Z(CmTK~_T)bM{+Z`J?F9p(QgwUqpy(O&w0^{lr4C$}vEmrdvPZuoy@ z&xZe}cCG(^Y}=auhc_+#zkl7_|0`#9{eSuF$^XwEKY{Nk{Ph0gpAX-^D-WZ%XGlv+ z;JNulmFkka{2$aFF*eO`1<|-Pte%^_n+W6{PW}2e=r7(3nKLmK=BSs z8^~;AF;IE(``7RPzkmLM;@|(lY2)Yb|G$3x0+%PhzW@9W>Su!N{PykJ|L@9g6`J;b32;<&uVY@KfA5=|IF6f|1(-@|Iciy`ai3w>i>-T z;{Qu~oBl8DYx=*Wx8eW7&f5PA+AIDq?yvuUX#48_pFh3_=YLS!|Kqz4zrXzdPxrgL zX_?+KGBU(+QZs(co!I+-&HM%bA3S{e|J}RK|3AF{^8e$YX8 zy?Oor&Fh!{U%!0u|K*Ek|6jd$`v2Xl=iqi9B=3XL;V01jCO`lG|Ibg$_@KAhnF*P) zd1;w{m&}~@|M>AU|F7JA_W#aFg z=H2K2Z((T!nodAz*_yL(~ zK#y~5=?0_*Bo3lMX#o|3(j)|f?E3!w=l}2De*XXV^(Q#pe*60U|JSe3bo}MV|L%u1*I1-{r&%!&)@!o?xzLcVf+bl7wOl}Uw<$#FmTd4j%aCLbaaw>en$5H z?VET0zkcV@|Lgak{l9tt+5cPjU%>H=`_KM^@q_38Z`^(~FEK79q1fj4Ox z7Xx8-d{n$aO;zLnO*;?&-+T1@|NSQ}{XcZ_^8aI}ul_%N_QwCy=WhQ$eeTBp3s>&` zzjEW@|0_2i{Xcj4?*DUF?)|@b?cx7RHy{7Mdgtl?Yj;6u1CnNLgVM#r=l?-8EFFQ^ zAbjfqRQ%z~|F<8#`hVx~>;Lzjy!n6s$=m-Ap1%A4@Y(zSPhNZg-w*rj^+)jCurJ?z z`v2$V#QyaC{|6|B%fr-t`u6_=97EKB z)qMQ+|2-7H1KacE|LgZ(|AWf97wH&Fcc|J`Q@eDB%2|M#DR@caJ{ zUVQlf;Klp@51zmOfB*UW|M#B1|9|({yZ?8dy!n6Y$?N}DAHDj2`_cQI&!7JvlxIFu zm_C@-Z9L+?Vf)d%4Lgq2ZQXOGZ_}<5^SA9ezG2(mQ-`+gKYMA%fpZV{96tYX-_i4b z_a8g=|G@FH{|_BM_y5qb^ZySVJ^O$E;Zy(j9y|^{QyFxZ>+Zb={_one|NoBN`~L6P zx%dCJZ9D&O-n8}qhV`5NuUWJH|C-h7|F2!M{{OnQoBpp~x9$JNjiCFc_x#_ob>IK3 z+YkKTvFp(Pox6|!-?i`L|J?^bW}p4P|H!%jhmK$Pf8^Aa|3}Y&%BJi8PhPn7|MaCh z|Ic2z_y640d;c%oc=-Rq%}4()+aR zP+RBny=VWg+;CJ`;MIczvsy5|9g*| z_`mPS@&9`cAN#-i$dUiM4;}u$`_Pg9yAK}xzjHqn?>q2+$KHMackJ2of7|Ze|2OU2 z^?&2`oe;cr*Z&P$cKzP~qPOk-zkb`E{~LGg`@d=Tf&Y7toc@2{$myHndlvd z&Zq7;c)no!!3&jJ51eb>vj1$)=KZIqZasKr?v{gRmu^3Nan1H47dLM|c6rzKW0w!^ zIC|;$jw9#K?mTkt%J#!&FYi8n{=m*7XO?X{c&vBF(X-`S4_!)Jck-6c=3`gPcAmJQ zxcekHUfFTDb5wXV1cpQi{3i?=(3CW=qY5-I*rNzEFfgF-85kJ&kp)2EQja76;v*Xg z;xou26oC1RaQ;6qA7Lbv&j2$L#)laR3CLySb?gN;PugFO!F z&clpk{{R0!G9RRX5dQ;AGl;hT{~v{4Pk{d)RUYJ}2Ox8xnEC&Ixc5Oq=zMlG=klW( z2MRJ2=g6bU+yDQMY#k`TQ277RR=cPA0@iv(V~wCK62^=MIT9g{{R0`)Kh_v zlKSP*lAApmA1(KQk_WPWQ1m17LD7fI2L(SeA5 + + +Your application description here. + + + + + + diff --git a/src/acer386sx.c b/src/acer386sx.c new file mode 100644 index 000000000..4b6452583 --- /dev/null +++ b/src/acer386sx.c @@ -0,0 +1,33 @@ +#include "ibm.h" +#include "io.h" +#include "cpu.h" + +#include "acer386sx.h" + +static int acer_index = 0; +static uint8_t acer_regs[256]; + +void acer386sx_write(uint16_t addr, uint8_t val, void *priv) +{ + if (addr & 1) + acer_regs[acer_index] = val; + else + acer_index = val; +} + +uint8_t acer386sx_read(uint16_t addr, void *priv) +{ + if (addr & 1) + { + if ((acer_index >= 0xc0 || acer_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return acer_regs[acer_index]; + } + else + return acer_index; +} + +void acer386sx_init() +{ + io_sethandler(0x0022, 0x0002, acer386sx_read, NULL, NULL, acer386sx_write, NULL, NULL, NULL); +} diff --git a/src/acer386sx.h b/src/acer386sx.h new file mode 100644 index 000000000..729fbf708 --- /dev/null +++ b/src/acer386sx.h @@ -0,0 +1 @@ +void acer386sx_init(); diff --git a/src/acerm3a.c b/src/acerm3a.c new file mode 100644 index 000000000..c9a14f302 --- /dev/null +++ b/src/acerm3a.c @@ -0,0 +1,29 @@ +#include "ibm.h" +#include "io.h" +#include "acerm3a.h" + +static int acerm3a_index; + +static void acerm3a_out(uint16_t port, uint8_t val, void *p) +{ + if (port == 0xea) + acerm3a_index = val; +} + +static uint8_t acerm3a_in(uint16_t port, void *p) +{ + if (port == 0xeb) + { + switch (acerm3a_index) + { + case 2: + return 0xfd; + } + } + return 0xff; +} + +void acerm3a_io_init() +{ + io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, NULL); +} diff --git a/src/acerm3a.h b/src/acerm3a.h new file mode 100644 index 000000000..370d7200f --- /dev/null +++ b/src/acerm3a.h @@ -0,0 +1 @@ +void acerm3a_io_init(); diff --git a/src/ali1429.c b/src/ali1429.c new file mode 100644 index 000000000..29b654b14 --- /dev/null +++ b/src/ali1429.c @@ -0,0 +1,86 @@ +#include +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "cpu.h" + +#include "ali1429.h" + +static int ali1429_index; +static uint8_t ali1429_regs[256]; + +static void ali1429_recalc() +{ + int c; + + for (c = 0; c < 8; c++) + { + uint32_t base = 0xc0000 + (c << 15); + if (ali1429_regs[0x13] & (1 << c)) + { + switch (ali1429_regs[0x14] & 3) + { + case 0: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + } + else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); +} + +void ali1429_write(uint16_t port, uint8_t val, void *priv) +{ + int c; + + if (!(port & 1)) + ali1429_index = val; + else + { + ali1429_regs[ali1429_index] = val; +// pclog("ALI1429 write %02X %02X %04X:%04X %i\n",ali1429_index,val,CS,pc,ins); + switch (ali1429_index) + { + case 0x13: + ali1429_recalc(); + break; + case 0x14: + shadowbios = val & 1; + shadowbios_write = val & 2; + ali1429_recalc(); + break; + } + } +} + +uint8_t ali1429_read(uint16_t port, void *priv) +{ + if (!(port & 1)) + return ali1429_index; + if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return ali1429_regs[ali1429_index]; +} + + +void ali1429_reset() +{ + memset(ali1429_regs, 0xff, 256); +} + +void ali1429_init() +{ + io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, NULL); +} diff --git a/src/ali1429.h b/src/ali1429.h new file mode 100644 index 000000000..5a64f2ec5 --- /dev/null +++ b/src/ali1429.h @@ -0,0 +1 @@ +void ali1429_init(); diff --git a/src/allegro-gui-configure.c b/src/allegro-gui-configure.c new file mode 100644 index 000000000..689284c46 --- /dev/null +++ b/src/allegro-gui-configure.c @@ -0,0 +1,636 @@ +#include "ibm.h" +#include "device.h" +#include "allegro-main.h" +#include "allegro-gui.h" +#include "cpu.h" +#include "fdd.h" +#include "gameport.h" +#include "model.h" +#include "sound.h" +#include "video.h" +#include "vid_voodoo.h" + +static int romstolist[ROM_MAX], listtomodel[ROM_MAX], romstomodel[ROM_MAX], modeltolist[ROM_MAX]; +static int settings_sound_to_list[20], settings_list_to_sound[20]; + +typedef struct allegro_list_t +{ + char name[256]; + int num; +} allegro_list_t; + +static allegro_list_t model_list[ROM_MAX+1]; +static allegro_list_t video_list[GFX_MAX+1]; +static allegro_list_t sound_list[GFX_MAX+1]; +static allegro_list_t cpumanu_list[4]; +static allegro_list_t cpu_list[32]; +static allegro_list_t joystick_list[32]; + +static char mem_size_str[10], mem_size_units[3]; + +static allegro_list_t cache_list[] = +{ + {"A little", 0}, + {"A bit", 1}, + {"Some", 2}, + {"A lot", 3}, + {"Infinite", 4}, + {"", -1} +}; + +static allegro_list_t vidspeed_list[] = +{ + {"8-bit", 0}, + {"Slow 16-bit", 1}, + {"Fast 16-bit", 2}, + {"Slow VLB/PCI", 3}, + {"Mid VLB/PCI", 4}, + {"Fast VLB/PCI", 5}, + {"", -1} +}; + +static allegro_list_t fdd_list[] = +{ + {"None", 0}, + {"5.25\" 360k", 1}, + {"5.25\" 1.2M", 2}, + {"5.25\" 1.2M Dual RPM", 3}, + {"3.5\" 720k", 4}, + {"3.5\" 1.44M", 5}, + {"3.5\" 1.44M 3-Mode", 6}, + {"3.5\" 2.88M", 7}, + {"", -1} +}; + +static void reset_list(); + +static char *list_proc_model(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (model_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return model_list[index].name; +} + +static char *list_proc_video(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (video_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return video_list[index].name; +} + +static char *list_proc_cache(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (cache_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return cache_list[index].name; +} + +static char *list_proc_vidspeed(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (vidspeed_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return vidspeed_list[index].name; +} + +static char *list_proc_sound(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (sound_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return sound_list[index].name; +} + +static char *list_proc_cpumanu(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (cpumanu_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return cpumanu_list[index].name; +} + +static char *list_proc_cpu(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (cpu_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return cpu_list[index].name; +} + +static char *list_proc_fdd(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (fdd_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return fdd_list[index].name; +} + +static char *list_proc_joystick(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (joystick_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return joystick_list[index].name; +} + +static int voodoo_config_proc(int msg, DIALOG *d, int c) +{ + int ret = d_button_proc(msg, d, c); + + if (ret == D_CLOSE) + { + deviceconfig_open(&voodoo_device); + return D_O_K; + } + + return ret; +} + + +static int video_config_proc(int msg, DIALOG *d, int c); +static int sound_config_proc(int msg, DIALOG *d, int c); +static int list_proc(int msg, DIALOG *d, int c); + +static DIALOG configure_dialog[] = +{ + {d_shadow_box_proc, 0, 0, 568,352,0,0xffffff,0,0, 0,0,0,0,0}, // 0 + + {d_button_proc, 226, 328, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 + {d_button_proc, 296, 328, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 + + {list_proc, 70*2, 12, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_model, 0, 0}, + + {list_proc, 70*2, 32, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_video, 0, 0}, + + {list_proc, 70*2, 52, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_cpumanu, 0, 0}, //5 + {list_proc, 70*2, 72, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_cpu, 0, 0}, + {d_list_proc, 70*2, 112, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_cache, 0, 0}, + {d_list_proc, 70*2, 132, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_vidspeed, 0, 0}, + {list_proc, 70*2, 152, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_sound, 0, 0}, //9 + + {d_edit_proc, 70*2, 236, 32, 14, 0, 0xffffff, 0, 0, 3, 0, mem_size_str, 0, 0}, + + {d_text_proc, 98*2, 236, 40, 10, 0, 0xffffff, 0, 0, 0, 0, mem_size_units, 0, 0}, + + {d_check_proc, 14*2, 252, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "CMS / Game Blaster", 0, 0}, + {d_check_proc, 14*2, 268, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Gravis Ultrasound", 0, 0}, + {d_check_proc, 14*2, 284, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Innovation SSI-2001", 0, 0}, + {d_check_proc, 14*2, 300, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Composite CGA", 0, 0}, + {d_check_proc, 14*2, 316, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Voodoo Graphics", 0, 0}, + + {d_text_proc, 16*2, 16, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Machine :", 0, 0}, + {d_text_proc, 16*2, 36, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Video :", 0, 0}, + {d_text_proc, 16*2, 56, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "CPU type :", 0, 0}, + {d_text_proc, 16*2, 76, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "CPU :", 0, 0}, + {d_text_proc, 16*2, 116, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Cache :", 0, 0}, + {d_text_proc, 16*2, 136, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Video speed :", 0, 0}, + {d_text_proc, 16*2, 156, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Soundcard :", 0, 0}, + {d_text_proc, 16*2, 236, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Memory :", 0, 0}, + + {d_check_proc, 14*2, 92, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Dynamic Recompiler", 0, 0}, + + {d_text_proc, 16*2, 176, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Drive A: :", 0, 0}, + {d_text_proc, 16*2, 196, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Drive B: :", 0, 0}, + {d_list_proc, 70*2, 172, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_fdd, 0, 0}, + {d_list_proc, 70*2, 192, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_fdd, 0, 0}, + + {video_config_proc, 452, 32+4, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, //30 + {sound_config_proc, 452, 152+4, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, + {voodoo_config_proc, 452, 316, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, + + {d_text_proc, 16*2, 216, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Joystick :", 0, 0}, + {d_list_proc, 70*2, 212, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_joystick, 0, 0}, //34 + + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +static int list_proc(int msg, DIALOG *d, int c) +{ + int old = d->d1; + int ret = d_list_proc(msg, d, c); + + if (d->d1 != old) + { + int new_model = model_list[configure_dialog[3].d1].num; + int new_cpu_m = configure_dialog[5].d1; + int new_cpu = configure_dialog[6].d1; + int new_dynarec = configure_dialog[25].flags & D_SELECTED; + int new_gfxcard = video_old_to_new(video_list[configure_dialog[4].d1].num); + int new_mem_size; + int cpu_flags; + + reset_list(); + + if (models[new_model].fixed_gfxcard) + configure_dialog[4].flags |= D_DISABLED; + else + configure_dialog[4].flags &= ~D_DISABLED; + + cpu_flags = models[new_model].cpu[new_cpu_m].cpus[new_cpu].cpu_flags; + configure_dialog[25].flags = (((cpu_flags & CPU_SUPPORTS_DYNAREC) && new_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC)) ? D_SELECTED : 0; + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + configure_dialog[25].flags |= D_DISABLED; + + sscanf(mem_size_str, "%i", &new_mem_size); + new_mem_size &= ~(models[new_model].ram_granularity - 1); + if (new_mem_size < models[new_model].min_ram) + new_mem_size = models[new_model].min_ram; + else if (new_mem_size > models[new_model].max_ram) + new_mem_size = models[new_model].max_ram; + sprintf(mem_size_str, "%i", new_mem_size); + + if (models[new_model].is_at) + sprintf(mem_size_units, "MB"); + else + sprintf(mem_size_units, "kB"); + + if (!video_card_has_config(new_gfxcard)) + configure_dialog[30].flags |= D_DISABLED; + else + configure_dialog[30].flags &= ~D_DISABLED; + + if (!sound_card_has_config(configure_dialog[9].d1)) + configure_dialog[31].flags |= D_DISABLED; + else + configure_dialog[31].flags &= ~D_DISABLED; + + return D_REDRAW; + } + + return ret; +} + +static int video_config_proc(int msg, DIALOG *d, int c) +{ + int ret = d_button_proc(msg, d, c); + + if (ret == D_CLOSE) + { + int new_gfxcard = video_old_to_new(video_list[configure_dialog[4].d1].num); + + deviceconfig_open(video_card_getdevice(new_gfxcard)); + return D_O_K; + } + + return ret; +} +static int sound_config_proc(int msg, DIALOG *d, int c) +{ + int ret = d_button_proc(msg, d, c); + + if (ret == D_CLOSE) + { + int new_sndcard = sound_list[configure_dialog[9].d1].num; + + deviceconfig_open(sound_card_getdevice(new_sndcard)); + return D_O_K; + } + + return ret; +} + +static void reset_list() +{ + int model = model_list[configure_dialog[3].d1].num; + int cpumanu = configure_dialog[5].d1; + int cpu = configure_dialog[6].d1; + int c; + + memset(cpumanu_list, 0, sizeof(cpumanu_list)); + memset(cpu_list, 0, sizeof(cpu_list)); + + c = 0; + while (models[model].cpu[c].cpus != NULL && c < 3) + { + strcpy(cpumanu_list[c].name, models[model].cpu[c].name); + cpumanu_list[c].num = c; + c++; + } + + if (cpumanu >= c) + cpumanu = configure_dialog[6].d1 = c-1; + + c = 0; + while (models[model].cpu[cpumanu].cpus[c].cpu_type != -1) + { + strcpy(cpu_list[c].name, models[model].cpu[cpumanu].cpus[c].name); + cpu_list[c].num = c; + c++; + } + + if (cpu >= c) + cpu = configure_dialog[7].d1 = c-1; +} + +int settings_configure() +{ + int c, d; + int cpu_flags; + + memset(model_list, 0, sizeof(model_list)); + memset(video_list, 0, sizeof(video_list)); + memset(sound_list, 0, sizeof(sound_list)); + + for (c = 0; c < ROM_MAX; c++) + romstolist[c] = 0; + c = d = 0; + while (models[c].id != -1) + { + pclog("INITDIALOG : %i %i %i\n",c,models[c].id,romspresent[models[c].id]); + if (romspresent[models[c].id]) + { + strcpy(model_list[d].name, models[c].name); + model_list[d].num = c; + if (c == model) + configure_dialog[3].d1 = d; + d++; + } + c++; + } + + if (models[model].fixed_gfxcard) + configure_dialog[4].flags |= D_DISABLED; + else + configure_dialog[4].flags &= ~D_DISABLED; + + c = d = 0; + while (1) + { + char *s = video_card_getname(c); + + if (!s[0]) + break; +pclog("video_card_available : %i\n", c); + if (video_card_available(c)) + { + strcpy(video_list[d].name, video_card_getname(c)); + video_list[d].num = video_new_to_old(c); + if (video_new_to_old(c) == gfxcard) + configure_dialog[4].d1 = d; + d++; + } + + c++; + } + + if (!video_card_has_config(video_old_to_new(gfxcard))) + configure_dialog[30].flags |= D_DISABLED; + else + configure_dialog[30].flags &= ~D_DISABLED; + + c = d = 0; + while (1) + { + char *s = sound_card_getname(c); + + if (!s[0]) + break; + + if (sound_card_available(c)) + { + strcpy(sound_list[d].name, sound_card_getname(c)); + sound_list[d].num = c; + if (c == sound_card_current) + configure_dialog[9].d1 = d; + d++; + } + + c++; + } + + c = 0; + while (joystick_get_name(c)) + { + strcpy(joystick_list[c].name, joystick_get_name(c)); + if (c == joystick_type) + configure_dialog[34].d1 = c; + + c++; + } + + if (!sound_card_has_config(configure_dialog[9].d1)) + configure_dialog[31].flags |= D_DISABLED; + else + configure_dialog[31].flags &= ~D_DISABLED; + + configure_dialog[5].d1 = cpu_manufacturer; + configure_dialog[6].d1 = cpu; + configure_dialog[7].d1 = cache; + configure_dialog[8].d1 = video_speed; + reset_list(); +// strcpy(cpumanu_str, models[romstomodel[romset]].cpu[cpu_manufacturer].name); +// strcpy(cpu_str, models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].name); +// strcpy(cache_str, cache_str_list[cache]); +// strcpy(vidspeed_str, vidspeed_str_list[video_speed]); + +// strcpy(soundcard_str, sound_card_getname(sound_card_current)); + + if (GAMEBLASTER) + configure_dialog[12].flags |= D_SELECTED; + else + configure_dialog[12].flags &= ~D_SELECTED; + + if (GUS) + configure_dialog[13].flags |= D_SELECTED; + else + configure_dialog[13].flags &= ~D_SELECTED; + + if (SSI2001) + configure_dialog[14].flags |= D_SELECTED; + else + configure_dialog[14].flags &= ~D_SELECTED; + + if (cga_comp) + configure_dialog[15].flags |= D_SELECTED; + else + configure_dialog[15].flags &= ~D_SELECTED; + + if (voodoo_enabled) + configure_dialog[16].flags |= D_SELECTED; + else + configure_dialog[16].flags &= ~D_SELECTED; + + if (models[model].is_at) + sprintf(mem_size_str, "%i", mem_size / 1024); + else + sprintf(mem_size_str, "%i", mem_size); + + if (models[model].is_at) + sprintf(mem_size_units, "MB"); + else + sprintf(mem_size_units, "kB"); + + cpu_flags = models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_flags; + configure_dialog[25].flags = (((cpu_flags & CPU_SUPPORTS_DYNAREC) && cpu_use_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC)) ? D_SELECTED : 0; + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + configure_dialog[25].flags |= D_DISABLED; + + configure_dialog[28].d1 = fdd_get_type(0); + configure_dialog[29].d1 = fdd_get_type(1); + + while (1) + { + position_dialog(configure_dialog, SCREEN_W/2 - configure_dialog[0].w/2, SCREEN_H/2 - configure_dialog[0].h/2); + + c = popup_dialog(configure_dialog, 1); + + position_dialog(configure_dialog, -(SCREEN_W/2 - configure_dialog[0].w/2), -(SCREEN_H/2 - configure_dialog[0].h/2)); + + if (c == 1) + { + int new_model = model_list[configure_dialog[3].d1].num; + int new_gfxcard = video_list[configure_dialog[4].d1].num; + int new_sndcard = sound_list[configure_dialog[9].d1].num; + int new_cpu_m = configure_dialog[5].d1; + int new_cpu = configure_dialog[6].d1; + int new_mem_size; + int new_has_fpu = (models[new_model].cpu[new_cpu_m].cpus[new_cpu].cpu_type >= CPU_i486DX) ? 1 : 0; + int new_GAMEBLASTER = (configure_dialog[12].flags & D_SELECTED) ? 1 : 0; + int new_GUS = (configure_dialog[13].flags & D_SELECTED) ? 1 : 0; + int new_SSI2001 = (configure_dialog[14].flags & D_SELECTED) ? 1 : 0; + int new_voodoo = (configure_dialog[16].flags & D_SELECTED) ? 1 : 0; + int new_dynarec = (configure_dialog[25].flags & D_SELECTED) ? 1 : 0; + int new_fda = configure_dialog[28].d1; + int new_fdb = configure_dialog[29].d1; + + sscanf(mem_size_str, "%i", &new_mem_size); + new_mem_size &= ~(models[new_model].ram_granularity - 1); + if (new_mem_size < models[new_model].min_ram) + new_mem_size = models[new_model].min_ram; + else if (new_mem_size > models[new_model].max_ram) + new_mem_size = models[new_model].max_ram; + if (models[new_model].is_at) + new_mem_size *= 1024; + + if (new_model != model || new_gfxcard != gfxcard || new_mem_size != mem_size || + new_has_fpu != hasfpu || new_GAMEBLASTER != GAMEBLASTER || new_GUS != GUS || + new_SSI2001 != SSI2001 || new_sndcard != sound_card_current || new_voodoo != voodoo_enabled || + new_dynarec != cpu_use_dynarec || new_fda != fdd_get_type(0) || new_fdb != fdd_get_type(1)) + { + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) != 1) + continue; + + model = new_model; + romset = model_getromset(); + gfxcard = new_gfxcard; + mem_size = new_mem_size; + cpu_manufacturer = new_cpu_m; + cpu = new_cpu; + GAMEBLASTER = new_GAMEBLASTER; + GUS = new_GUS; + SSI2001 = new_SSI2001; + sound_card_current = new_sndcard; + voodoo_enabled = new_voodoo; + cpu_use_dynarec = new_dynarec; + + mem_resize(); + loadbios(); + resetpchard(); + + fdd_set_type(0, new_fda); + fdd_set_type(1, new_fdb); + } + + video_speed = configure_dialog[8].d1; + + cga_comp = (configure_dialog[15].flags & D_SELECTED) ? 1 : 0; + + cpu_manufacturer = new_cpu_m; + cpu = new_cpu; + cpu_set(); + + cache = configure_dialog[7].d1; + mem_updatecache(); + + joystick_type = configure_dialog[34].d1; + gameport_update_joystick_type(); + + saveconfig(); + + speedchanged(); + + return D_O_K; + } + + if (c == 2) + return D_O_K; + } + + return D_O_K; +} + diff --git a/src/allegro-gui-deviceconfig.c b/src/allegro-gui-deviceconfig.c new file mode 100644 index 000000000..cc87058db --- /dev/null +++ b/src/allegro-gui-deviceconfig.c @@ -0,0 +1,303 @@ +#include "ibm.h" +#include "device.h" +#include "allegro-main.h" +#include "allegro-gui.h" +#include "config.h" + +static device_t *config_device; + +#define MAX_CONFIG_SIZE 64 +#define MAX_CONFIG_SELECTIONS 8 + +static device_config_selection_t *config_selections[MAX_CONFIG_SELECTIONS]; + +#define list_proc_device_func(i) \ + static char *list_proc_device_ ## i(int index, int *list_size) \ + { \ + device_config_selection_t *config = config_selections[i]; \ + \ + if (index < 0) \ + { \ + int c = 0; \ + \ + while (config[c].description[0]) \ + c++; \ + \ + *list_size = c; \ + return NULL; \ + } \ + \ + return config[index].description; \ + } + +list_proc_device_func(0) +list_proc_device_func(1) +list_proc_device_func(2) +list_proc_device_func(3) +list_proc_device_func(4) +list_proc_device_func(5) +list_proc_device_func(6) +list_proc_device_func(7) + +static DIALOG deviceconfig_dialog[MAX_CONFIG_SIZE] = +{ + {d_shadow_box_proc, 0, 0, 568,332,0,0xffffff,0,0, 0,0,0,0,0} // 0 +}; + +void deviceconfig_open(device_t *device) +{ + DIALOG *d; + device_config_t *config = device->config; + int y = 10; + int dialog_pos = 1; + int list_pos = 0; + int c; + int id_ok, id_cancel; + + memset((void *)((uintptr_t)deviceconfig_dialog) + sizeof(DIALOG), 0, sizeof(deviceconfig_dialog) - sizeof(DIALOG)); + deviceconfig_dialog[0].x = deviceconfig_dialog[0].y = 0; + + while (config->type != -1) + { + d = &deviceconfig_dialog[dialog_pos]; + + switch (config->type) + { + case CONFIG_BINARY: + d->x = 32; + d->y = y; + + d->w = 118*2; + d->h = 15; + + d->dp = config->description; + d->proc = d_check_proc; + + d->flags = config_get_int(device->name, config->name, config->default_int) ? D_SELECTED : 0; + d->bg = 0xffffff; + d->fg = 0; + + dialog_pos++; + + y += 20; + break; + + case CONFIG_SELECTION: + if (list_pos >= MAX_CONFIG_SELECTIONS) + break; + + d->x = 32; + d->y = y; + + d->w = 80; + d->h = 15; + + d->dp = config->description; + d->proc = d_text_proc; + + d->flags = 0; + d->bg = 0xffffff; + d->fg = 0; + + d++; + + d->x = 250; + d->y = y; + + d->w = 304; + d->h = 20; + + switch (list_pos) + { + case 0 : d->dp = list_proc_device_0; break; + case 1 : d->dp = list_proc_device_1; break; + case 2 : d->dp = list_proc_device_2; break; + case 3 : d->dp = list_proc_device_3; break; + case 4 : d->dp = list_proc_device_4; break; + case 5 : d->dp = list_proc_device_5; break; + case 6 : d->dp = list_proc_device_6; break; + case 7 : d->dp = list_proc_device_7; break; + } + d->proc = d_list_proc; + + d->flags = 0; + d->bg = 0xffffff; + d->fg = 0; + + config_selections[list_pos++] = config->selection; + + c = 0; + while (config->selection[c].description[0]) + { + if (config_get_int(device->name, config->name, config->default_int) == config->selection[c].value) + d->d1 = c; + c++; + } + + dialog_pos += 2; + + y += 20; + break; + + case CONFIG_MIDI: + break; + } + + config++; + + if (dialog_pos >= MAX_CONFIG_SIZE-3) + break; + } + + d = &deviceconfig_dialog[dialog_pos]; + + id_ok = dialog_pos; + id_cancel = dialog_pos + 1; + + d->x = 226; + d->y = y+8; + + d->w = 50; + d->h = 16; + + d->dp = "OK"; + d->proc = d_button_proc; + + d->flags = D_EXIT; + d->bg = 0xffffff; + d->fg = 0; + + d++; + + d->x = 296; + d->y = y+8; + + d->w = 50; + d->h = 16; + + d->dp = "Cancel"; + d->proc = d_button_proc; + + d->flags = D_EXIT; + d->bg = 0xffffff; + d->fg = 0; + + deviceconfig_dialog[0].h = y + 28; + + config_device = device; + + while (1) + { + position_dialog(deviceconfig_dialog, SCREEN_W/2 - deviceconfig_dialog[0].w/2, SCREEN_H/2 - deviceconfig_dialog[0].h/2); + + c = popup_dialog(deviceconfig_dialog, 1); + + position_dialog(deviceconfig_dialog, -(SCREEN_W/2 - deviceconfig_dialog[0].w/2), -(SCREEN_H/2 - deviceconfig_dialog[0].h/2)); + + if (c == id_ok) + { + int changed = 0; + + dialog_pos = 1; + config = device->config; + + while (config->type != -1) + { + int val; + + d = &deviceconfig_dialog[dialog_pos]; + + switch (config->type) + { + case CONFIG_BINARY: + val = (d->flags & D_SELECTED) ? 1 : 0; + + if (val != config_get_int(device->name, config->name, config->default_int)) + changed = 1; + + dialog_pos++; + break; + + case CONFIG_SELECTION: + if (list_pos >= MAX_CONFIG_SELECTIONS) + break; + + d++; + + val = config->selection[d->d1].value; + + if (val != config_get_int(device->name, config->name, config->default_int)) + changed = 1; + + dialog_pos += 2; + break; + + case CONFIG_MIDI: + break; + } + + config++; + + if (dialog_pos >= MAX_CONFIG_SIZE-3) + break; + } + + if (!changed) + return; + + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) != 1) + continue; + + dialog_pos = 1; + config = device->config; + + while (config->type != -1) + { + int val; + + d = &deviceconfig_dialog[dialog_pos]; + + switch (config->type) + { + case CONFIG_BINARY: + val = (d->flags & D_SELECTED) ? 1 : 0; + + config_set_int(config_device->name, config->name, val); + + dialog_pos++; + break; + + case CONFIG_SELECTION: + if (list_pos >= MAX_CONFIG_SELECTIONS) + break; + + d++; + + val = config->selection[d->d1].value; + + config_set_int(config_device->name, config->name, val); + + dialog_pos += 2; + break; + + case CONFIG_MIDI: + break; + } + + config++; + + if (dialog_pos >= MAX_CONFIG_SIZE-3) + break; + } + + saveconfig(); + + resetpchard(); + + return; + } + + if (c == id_cancel) + break; + } +} diff --git a/src/allegro-gui-hdconf.c b/src/allegro-gui-hdconf.c new file mode 100644 index 000000000..1dcf2aa1f --- /dev/null +++ b/src/allegro-gui-hdconf.c @@ -0,0 +1,513 @@ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE + +#include +#include "ibm.h" +#include "device.h" +#include "ide.h" +#include "allegro-main.h" +#include "allegro-gui.h" + +static char hd_path[4][260]; +static char hd_sectors[4][10]; +static char hd_heads[4][10]; +static char hd_cylinders[4][10]; +static char hd_size[4][20]; + +static char hd_path_new[260]; +static char hd_sectors_new[10]; +static char hd_heads_new[10]; +static char hd_cylinders_new[10]; +static char hd_size_new[20]; + +static int new_cdrom_channel; + +static PcemHDC hdc_new[4]; + +static DIALOG hdparams_dialog[]= +{ + {d_shadow_box_proc, 0, 0, 194*2,86,0,0xffffff,0,0, 0,0,0,0,0}, // 0 + + {d_button_proc, 126, 66, 50, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 + {d_button_proc, 196, 66, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 + + {d_text_proc, 7*2, 6, 170, 10, 0, 0xffffff, 0, 0, 0, 0, "Initial settings are based on file size", 0, 0}, + + {d_text_proc, 7*2, 22, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 22, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 22, 28, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_edit_proc, 44*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 2, 0, hd_sectors_new, 0, 0}, + {d_edit_proc, 92*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 3, 0, hd_heads_new, 0, 0}, + {d_edit_proc, 168*2, 22, 24*2, 12, 0, 0xffffff, 0, 0, 5, 0, hd_cylinders_new, 0, 0}, + {d_text_proc, 7*2, 54, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size_new, 0, 0}, + + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +static int hdconf_open(int msg, DIALOG *d, int c) +{ + int drv = d->d2; + int ret = d_button_proc(msg, d, c); + + if (ret == D_EXIT) + { + char fn[260]; + int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; + + strcpy(fn, hd_path[drv]); + ret = file_select_ex("Please choose a disc image", fn, "IMG", 260, xsize, ysize); + if (ret) + { + uint64_t sz; + FILE *f = fopen64(fn, "rb"); + if (!f) + { + return D_REDRAW; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + sprintf(hd_sectors_new, "63"); + sprintf(hd_heads_new, "16"); + sprintf(hd_cylinders_new, "%i", (int)((sz / 512) / 16) / 63); + + while (1) + { + position_dialog(hdparams_dialog, SCREEN_W/2 - 186, SCREEN_H/2 - 86/2); + + ret = popup_dialog(hdparams_dialog, 1); + + position_dialog(hdparams_dialog, -(SCREEN_W/2 - 186), -(SCREEN_H/2 - 86/2)); + + if (ret == 1) + { + int spt, hpc, cyl; + sscanf(hd_sectors_new, "%i", &spt); + sscanf(hd_heads_new, "%i", &hpc); + sscanf(hd_cylinders_new, "%i", &cyl); + + if (spt > 63) + { + alert("Drive has too many sectors (maximum is 63)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (hpc > 128) + { + alert("Drive has too many heads (maximum is 128)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (cyl > 16383) + { + alert("Drive has too many cylinders (maximum is 16383)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + + hdc_new[drv].spt = spt; + hdc_new[drv].hpc = hpc; + hdc_new[drv].tracks = cyl; + + strcpy(hd_path[drv], fn); + sprintf(hd_sectors[drv], "%i", hdc_new[drv].spt); + sprintf(hd_heads[drv], "%i", hdc_new[drv].hpc); + sprintf(hd_cylinders[drv], "%i", hdc_new[drv].tracks); + sprintf(hd_size[drv], "Size : %imb", (((((uint64_t)hdc_new[drv].tracks*(uint64_t)hdc_new[drv].hpc)*(uint64_t)hdc_new[drv].spt)*512)/1024)/1024); + + return D_REDRAW; + } + + if (ret == 2) + break; + } + } + + return D_REDRAW; + } + + return ret; +} + +static int hdconf_new_file(int msg, DIALOG *d, int c) +{ + int ret = d_button_proc(msg, d, c); + + if (ret == D_EXIT) + { + char fn[260]; + int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; + + strcpy(fn, hd_path_new); + ret = file_select_ex("Please choose a disc image", fn, "IMG", 260, xsize, ysize); + if (ret) + strcpy(hd_path_new, fn); + + return D_REDRAW; + } + + return ret; +} + +static DIALOG hdnew_dialog[]= +{ + {d_shadow_box_proc, 0, 0, 194*2,86,0,0xffffff,0,0, 0,0,0,0,0}, // 0 + + {d_button_proc, 126, 66, 50, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 + {d_button_proc, 196, 66, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 + + {d_edit_proc, 7*2, 6, 136*2, 10, 0, 0xffffff, 0, 0, 0, 0, hd_path_new, 0, 0}, + {hdconf_new_file, 143*2, 6, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "...", 0, 0}, + + {d_text_proc, 7*2, 22, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 22, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 22, 28, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_edit_proc, 44*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 2, 0, hd_sectors_new, 0, 0}, + {d_edit_proc, 92*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 3, 0, hd_heads_new, 0, 0}, + {d_edit_proc, 168*2, 22, 24*2, 12, 0, 0xffffff, 0, 0, 5, 0, hd_cylinders_new, 0, 0}, +// {d_text_proc, 7*2, 54, 136, 12, 0, -1, 0, 0, 0, 0, hd_size_new, 0, 0}, + + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +static int create_hd(char *fn, int cyl, int hpc, int spt) +{ + int c; + int e; + uint8_t buf[512]; + FILE *f = fopen64(hd_path_new, "wb"); + e = errno; + if (!f) + { + alert("Can't open file for write", NULL, NULL, "OK", NULL, 0, 0); + return -1; + } + memset(buf, 0, 512); + for (c = 0; c < (cyl * hpc * spt); c++) + { + fwrite(buf, 512, 1, f); + } + fclose(f); +} + +static int hdconf_new(int msg, DIALOG *d, int c) +{ + int drv = d->d2; + int ret = d_button_proc(msg, d, c); + + if (ret == D_EXIT) + { + sprintf(hd_sectors_new, "63"); + sprintf(hd_heads_new, "16"); + sprintf(hd_cylinders_new, "511"); + strcpy(hd_path_new, ""); + + while (1) + { + position_dialog(hdnew_dialog, SCREEN_W/2 - 186, SCREEN_H/2 - 86/2); + + ret = popup_dialog(hdnew_dialog, 1); + + position_dialog(hdnew_dialog, -(SCREEN_W/2 - 186), -(SCREEN_H/2 - 86/2)); + + if (ret == 1) + { + int spt, hpc, cyl; + int c, d; + FILE *f; + uint8_t *buf; + + sscanf(hd_sectors_new, "%i", &spt); + sscanf(hd_heads_new, "%i", &hpc); + sscanf(hd_cylinders_new, "%i", &cyl); + + if (spt > 63) + { + alert("Drive has too many sectors (maximum is 63)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (hpc > 128) + { + alert("Drive has too many heads (maximum is 128)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (cyl > 16383) + { + alert("Drive has too many cylinders (maximum is 16383)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (create_hd(hd_path_new, cyl, hpc, spt)) + return D_REDRAW; + + alert("Remember to partition and format the new drive", NULL, NULL, "OK", NULL, 0, 0); + + hdc_new[drv].spt = spt; + hdc_new[drv].hpc = hpc; + hdc_new[drv].tracks = cyl; + + strcpy(hd_path[drv], hd_path_new); + sprintf(hd_sectors[drv], "%i", hdc_new[drv].spt); + sprintf(hd_heads[drv], "%i", hdc_new[drv].hpc); + sprintf(hd_cylinders[drv], "%i", hdc_new[drv].tracks); + sprintf(hd_size[drv], "Size : %imb", (((((uint64_t)hdc_new[drv].tracks*(uint64_t)hdc_new[drv].hpc)*(uint64_t)hdc_new[drv].spt)*512)/1024)/1024); + + return D_REDRAW; + } + + if (ret == 2) + break; + } + + return D_REDRAW; + } + + return ret; +} + +static int hdconf_eject(int msg, DIALOG *d, int c) +{ + int drv = d->d2; + int ret = d_button_proc(msg, d, c); + + if (ret == D_EXIT) + { + hdc_new[drv].spt = 0; + hdc_new[drv].hpc = 0; + hdc_new[drv].tracks = 0; + strcpy(hd_path[drv], ""); + sprintf(hd_sectors[drv], "%i", hdc_new[drv].spt); + sprintf(hd_heads[drv], "%i", hdc_new[drv].hpc); + sprintf(hd_cylinders[drv], "%i", hdc_new[drv].tracks); + sprintf(hd_size[drv], "Size : %imb", (((((uint64_t)hdc_new[drv].tracks*(uint64_t)hdc_new[drv].hpc)*(uint64_t)hdc_new[drv].spt)*512)/1024)/1024); + + return D_REDRAW; + } + + return ret; +} + +static int hdconf_radio_hd(int msg, DIALOG *d, int c); +static int hdconf_radio_cd(int msg, DIALOG *d, int c); + +static DIALOG hdconf_dialog[]= +{ + {d_shadow_box_proc, 0, 0, 210*2,354,0,0xffffff,0,0, 0,0,0,0,0}, // 0 + + {d_button_proc, 150, 334, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 + {d_button_proc, 220, 334, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 + + {d_text_proc, 7*2, 6, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "C:", 0, 0}, + {hdconf_radio_hd, 7*2, 22, 96, 12, 0, 0xffffff, 0, D_EXIT, 0, 0, "Hard drive", 0, 0}, // 4 + {hdconf_radio_cd, 100*2, 22, 64, 12, 0, 0xffffff, 0, D_EXIT, 0, 0, "CD-ROM", 0, 0}, // 5 + {d_edit_proc, 7*2, 38, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[0], 0, 0}, + {hdconf_open, 143*2, 38, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "...", 0, 0}, + {hdconf_new, 159*2, 38, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "New", 0, 0}, + {hdconf_eject, 183*2, 38, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Eject", 0, 0}, + + {d_text_proc, 7*2, 54, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 54, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 54, 28, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_edit_proc, 44*2, 54, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[0], 0, 0}, + {d_edit_proc, 92*2, 54, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[0], 0, 0}, + {d_edit_proc, 168*2, 54, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[0], 0, 0}, + {d_text_proc, 7*2, 54, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[0], 0, 0}, + + {d_text_proc, 7*2, 76, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "D:", 0, 0}, + {hdconf_radio_hd, 7*2, 92, 96, 12, 0, 0xffffff, 0, D_EXIT, 1, 0, "Hard drive", 0, 0}, // 18 + {hdconf_radio_cd, 100*2, 92, 64, 12, 0, 0xffffff, 0, D_EXIT, 1, 0, "CD-ROM", 0, 0}, // 19 + {d_edit_proc, 7*2, 108, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[1], 0, 0}, + {hdconf_open, 143*2, 108, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 1, "...", 0, 0}, + {hdconf_new, 159*2, 108, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 1, "New", 0, 0}, + {hdconf_eject, 183*2, 108, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 1, "Eject", 0, 0}, + + {d_edit_proc, 44*2, 124, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[1], 0, 0}, + {d_edit_proc, 92*2, 124, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[1], 0, 0}, + {d_edit_proc, 168*2, 124, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[1], 0, 0}, + {d_text_proc, 7*2, 124, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 124, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 124, 32, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_text_proc, 7*2, 140, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[1], 0, 0}, + + {d_text_proc, 7*2, 162, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "E:", 0, 0}, + {hdconf_radio_hd, 7*2, 178, 96, 12, 0, 0xffffff, 0, D_EXIT, 2, 0, "Hard drive", 0, 0}, // 32 + {hdconf_radio_cd, 100*2, 178, 64, 12, 0, 0xffffff, 0, D_EXIT, 2, 0, "CD-ROM", 0, 0}, // 33 + {d_edit_proc, 7*2, 194, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[2], 0, 0}, + {hdconf_open, 143*2, 194, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 2, "...", 0, 0}, + {hdconf_new, 159*2, 194, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 2, "New", 0, 0}, + {hdconf_eject, 183*2, 194, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 2, "Eject", 0, 0}, + + {d_edit_proc, 44*2, 210, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[2], 0, 0}, + {d_edit_proc, 92*2, 210, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[2], 0, 0}, + {d_edit_proc, 168*2, 210, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[2], 0, 0}, + {d_text_proc, 7*2, 210, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 210, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 210, 32, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_text_proc, 7*2, 226, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[2], 0, 0}, + + {d_text_proc, 7*2, 248, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "F:", 0, 0}, + {hdconf_radio_hd, 7*2, 264, 96, 12, 0, 0xffffff, 0, D_EXIT, 3, 0, "Hard drive", 0, 0}, // 46 + {hdconf_radio_cd, 100*2, 264, 64, 12, 0, 0xffffff, 0, D_EXIT, 3, 0, "CD-ROM", 0, 0}, // 47 + {d_edit_proc, 7*2, 280, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[3], 0, 0}, + {hdconf_open, 143*2, 280, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 3, "...", 0, 0}, + {hdconf_new, 159*2, 280, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 3, "New", 0, 0}, + {hdconf_eject, 183*2, 280, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 3, "Eject", 0, 0}, + + {d_edit_proc, 44*2, 296, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[3], 0, 0}, + {d_edit_proc, 92*2, 296, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[3], 0, 0}, + {d_edit_proc, 168*2, 296, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[3], 0, 0}, + {d_text_proc, 7*2, 296, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 296, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 296, 32, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_text_proc, 7*2, 312, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[3], 0, 0}, + + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +static void update_hdd_cdrom() +{ + if (new_cdrom_channel == 0) + { + hdconf_dialog[4].flags &= ~D_SELECTED; + hdconf_dialog[5].flags |= D_SELECTED; + } + else + { + hdconf_dialog[4].flags |= D_SELECTED; + hdconf_dialog[5].flags &= ~D_SELECTED; + } + if (new_cdrom_channel == 1) + { + hdconf_dialog[18].flags &= ~D_SELECTED; + hdconf_dialog[19].flags |= D_SELECTED; + } + else + { + hdconf_dialog[18].flags |= D_SELECTED; + hdconf_dialog[19].flags &= ~D_SELECTED; + } + if (new_cdrom_channel == 2) + { + hdconf_dialog[32].flags &= ~D_SELECTED; + hdconf_dialog[33].flags |= D_SELECTED; + } + else + { + hdconf_dialog[32].flags |= D_SELECTED; + hdconf_dialog[33].flags &= ~D_SELECTED; + } + if (new_cdrom_channel == 3) + { + hdconf_dialog[46].flags &= ~D_SELECTED; + hdconf_dialog[47].flags |= D_SELECTED; + } + else + { + hdconf_dialog[46].flags |= D_SELECTED; + hdconf_dialog[47].flags &= ~D_SELECTED; + } +} + +static int hdconf_radio_hd(int msg, DIALOG *d, int c) +{ + int ret = d_radio_proc(msg, d, c); + + if (ret == D_CLOSE) + { + if (new_cdrom_channel == d->d1) + { + new_cdrom_channel = -1; + update_hdd_cdrom(); + } + + return D_REDRAW; + } + + return ret; +} +static int hdconf_radio_cd(int msg, DIALOG *d, int c) +{ + int ret = d_radio_proc(msg, d, c); + + if (ret == D_CLOSE) + { + if (new_cdrom_channel != d->d1) + { + new_cdrom_channel = d->d1; + update_hdd_cdrom(); + } + + return D_REDRAW; + } + + return ret; +} + +int disc_hdconf() +{ + int c; + int changed=0; + + hdc_new[0] = hdc[0]; + hdc_new[1] = hdc[1]; + hdc_new[2] = hdc[2]; + hdc_new[3] = hdc[3]; + strcpy(hd_path[0], ide_fn[0]); + strcpy(hd_path[1], ide_fn[1]); + strcpy(hd_path[2], ide_fn[2]); + strcpy(hd_path[3], ide_fn[3]); + sprintf(hd_sectors[0], "%i", hdc[0].spt); + sprintf(hd_sectors[1], "%i", hdc[1].spt); + sprintf(hd_sectors[2], "%i", hdc[2].spt); + sprintf(hd_sectors[3], "%i", hdc[3].spt); + sprintf(hd_heads[0], "%i", hdc[0].hpc); + sprintf(hd_heads[1], "%i", hdc[1].hpc); + sprintf(hd_heads[2], "%i", hdc[2].hpc); + sprintf(hd_heads[3], "%i", hdc[3].hpc); + sprintf(hd_cylinders[0], "%i", hdc[0].tracks); + sprintf(hd_cylinders[1], "%i", hdc[1].tracks); + sprintf(hd_cylinders[2], "%i", hdc[2].tracks); + sprintf(hd_cylinders[3], "%i", hdc[3].tracks); + sprintf(hd_size[0], "Size : %imb", (((((uint64_t)hdc[0].tracks*(uint64_t)hdc[0].hpc)*(uint64_t)hdc[0].spt)*512)/1024)/1024); + sprintf(hd_size[1], "Size : %imb", (((((uint64_t)hdc[1].tracks*(uint64_t)hdc[1].hpc)*(uint64_t)hdc[1].spt)*512)/1024)/1024); + sprintf(hd_size[2], "Size : %imb", (((((uint64_t)hdc[2].tracks*(uint64_t)hdc[2].hpc)*(uint64_t)hdc[2].spt)*512)/1024)/1024); + sprintf(hd_size[3], "Size : %imb", (((((uint64_t)hdc[3].tracks*(uint64_t)hdc[3].hpc)*(uint64_t)hdc[3].spt)*512)/1024)/1024); + + new_cdrom_channel = cdrom_channel; + + update_hdd_cdrom(); + + while (1) + { + position_dialog(hdconf_dialog, SCREEN_W/2 - hdconf_dialog[0].w/2, SCREEN_H/2 - hdconf_dialog[0].h/2); + + c = popup_dialog(hdconf_dialog, 1); + + position_dialog(hdconf_dialog, -(SCREEN_W/2 - hdconf_dialog[0].w/2), -(SCREEN_H/2 - hdconf_dialog[0].h/2)); + + if (c == 1) + { + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) + { + hdc[0] = hdc_new[0]; + hdc[1] = hdc_new[1]; + hdc[2] = hdc_new[2]; + hdc[3] = hdc_new[3]; + + strcpy(ide_fn[0], hd_path[0]); + strcpy(ide_fn[1], hd_path[1]); + strcpy(ide_fn[2], hd_path[2]); + strcpy(ide_fn[3], hd_path[3]); + + cdrom_channel = new_cdrom_channel; + + saveconfig(); + + resetpchard(); + + return D_O_K; + } + } + if (c == 2) + return D_O_K; + } + + return D_O_K; +} diff --git a/src/allegro-gui.c b/src/allegro-gui.c new file mode 100644 index 000000000..e29f8d1f9 --- /dev/null +++ b/src/allegro-gui.c @@ -0,0 +1,226 @@ +#include "ibm.h" +#include "device.h" +#include "allegro-main.h" +#include "allegro-gui.h" +#include "disc.h" +#include "ide.h" + +static int file_return(void) +{ + return D_CLOSE; +} + +static int file_exit(void) +{ + quited = 1; + return D_CLOSE; +} + +static int file_reset(void) +{ + resetpchard(); + return D_CLOSE; +} + +static int file_cad(void) +{ + resetpc_cad(); + return D_CLOSE; +} + + +static MENU file_menu[]= +{ + {"&Return", file_return, NULL, 0, NULL}, + {"&Hard Reset", file_reset, NULL, 0, NULL}, + {"&Ctrl+Alt+Del", file_cad, NULL, 0, NULL}, + {"E&xit", file_exit, NULL, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static int disc_load_a() +{ + char fn[260]; + int ret; + int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; + strcpy(fn, discfns[0]); + ret = file_select_ex("Please choose a disc image", fn, "IMG;IMA;FDI", 260, xsize, ysize); + if (ret) + { + disc_close(0); + disc_load(0, fn); + saveconfig(); + } + return D_O_K; +} + +static int disc_load_b() +{ + char fn[260]; + int ret; + int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; + strcpy(fn, discfns[1]); + ret = file_select_ex("Please choose a disc image", fn, "IMG;IMA;FDI", 260, xsize, ysize); + if (ret) + { + disc_close(1); + disc_load(1, fn); + saveconfig(); + } + return D_O_K; +} + +static int disc_eject_a() +{ + disc_close(0); + saveconfig(); + + return D_O_K; +} + +static int disc_eject_b() +{ + disc_close(1); + saveconfig(); + + return D_O_K; +} + +static MENU disc_menu[]= +{ + {"Load drive &A:...", disc_load_a, NULL, 0, NULL}, + {"Load drive &B:...", disc_load_b, NULL, 0, NULL}, + {"&Eject drive &A:", disc_eject_a, NULL, 0, NULL}, + {"Eject drive &B:", disc_eject_b, NULL, 0, NULL}, + {"&Configure hard discs...", disc_hdconf, NULL, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static MENU cdrom_menu[]; + +static void cdrom_update() +{ + int c; + + for (c = 0; cdrom_menu[c].text; c++) + cdrom_menu[c].flags = 0; + + if (!cdrom_enabled) + cdrom_menu[0].flags = D_SELECTED; + else + cdrom_menu[1].flags = D_SELECTED; + + return D_O_K; +} + +static int cdrom_disabled() +{ + if (!cdrom_enabled) + return D_O_K; + + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) + { + atapi->exit(); + cdrom_enabled = 0; + saveconfig(); + resetpchard(); + cdrom_update(); + } + + return D_O_K; +} + +static int cdrom_empty() +{ + if (cdrom_enabled) + { + atapi->exit(); + cdrom_drive = -1; + cdrom_null_open(cdrom_drive); + return D_O_K; + } + + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) + { + cdrom_drive = -1; + cdrom_enabled = 1; + cdrom_null_open(cdrom_drive); + saveconfig(); + resetpchard(); + cdrom_update(); + } +} + +static int cdrom_dev() +{ + if (cdrom_enabled) + { + atapi->exit(); + cdrom_drive = 1; + ioctl_open(cdrom_drive); + return D_O_K; + } + + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) + { + cdrom_drive = 1; + cdrom_enabled = 1; + ioctl_open(cdrom_drive); + saveconfig(); + resetpchard(); + cdrom_update(); + } +} + +static MENU cdrom_menu[] = +{ + {"&Disabled", cdrom_disabled, NULL, 0, NULL}, + {"&Empty", cdrom_empty, NULL, 0, NULL}, + {"/dev/cdrom", cdrom_dev, NULL, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static MENU settings_menu[]= +{ + {"&Configure...", settings_configure, NULL, 0, NULL}, + {"CD-ROM", NULL, cdrom_menu, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static MENU main_menu[]= +{ + {"&File", NULL, file_menu, 0, NULL}, + {"&Disc", NULL, disc_menu, 0, NULL}, + {"&Settings", NULL, settings_menu, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static DIALOG pcem_gui[]= +{ + {d_menu_proc, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, main_menu, NULL, NULL}, + {d_yield_proc, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, NULL, NULL, NULL}, + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +void gui_enter() +{ + DIALOG_PLAYER *dp; + int x = 1; + infocus = 0; + + dp = init_dialog(pcem_gui, 0); + show_mouse(screen); + while (x && !(mouse_b & 2) && !key[KEY_ESC]) + { + x = update_dialog(dp); + } + show_mouse(NULL); + shutdown_dialog(dp); + + clear(screen); + clear_keybuf(); + + infocus = 1; + + device_force_redraw(); +} diff --git a/src/allegro-gui.h b/src/allegro-gui.h new file mode 100644 index 000000000..acfa50c00 --- /dev/null +++ b/src/allegro-gui.h @@ -0,0 +1,12 @@ +void gui_enter(); + +extern int quited; + +extern int romspresent[ROM_MAX]; +extern int gfx_present[GFX_MAX]; + +int disc_hdconf(); + +int settings_configure(); + +void deviceconfig_open(device_t *device); diff --git a/src/allegro-joystick.c b/src/allegro-joystick.c new file mode 100644 index 000000000..f759aeedb --- /dev/null +++ b/src/allegro-joystick.c @@ -0,0 +1,49 @@ +#include "allegro-main.h" +#include "plat-joystick.h" +#include "device.h" +#include "gameport.h" + +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; + +int joysticks_present; + +void joystick_init() +{ + install_joystick(JOY_TYPE_AUTODETECT); + joysticks_present = num_joysticks; +} +void joystick_close() +{ +} +void joystick_poll() +{ + int c, d; + + poll_joystick(); + + for (c = 0; c < num_joysticks; c++) + { + plat_joystick_state[c].a[0] = joy[c].stick[0].axis[0].pos * 256; + plat_joystick_state[c].a[1] = joy[c].stick[0].axis[1].pos * 256; + for (d = 0; d < MAX_JOYSTICK_BUTTONS; d++) + plat_joystick_state[c].b[d] = joy[c].button[d].b; + } + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + if (c < num_joysticks) + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = plat_joystick_state[c].a[d]; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = plat_joystick_state[c].b[d]; + } + else + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = 0; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = 0; + } + } +} diff --git a/src/allegro-keyboard.c b/src/allegro-keyboard.c new file mode 100644 index 000000000..04c36c39d --- /dev/null +++ b/src/allegro-keyboard.c @@ -0,0 +1,49 @@ +#include "allegro-main.h" +#include "plat-keyboard.h" + +int pcem_key[272]; +int rawinputkey[272]; + +static int key_convert[128] = +{ + -1, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, /* , A, B, C, D, E, F, G*/ + 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, /* H, I, J, K, L, M, N, O*/ + 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, /* P, Q, R, S, T, U, V, W*/ + 0x2d, 0x15, 0x2c, 0x0b, 0x02, 0x03, 0x04, 0x05, /* X, Y, Z, 0, 1, 2, 3, 4*/ + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x52, 0x4f, 0x50, /* 5, 6, 7, 8, 9, p0, p1, p2*/ + 0x51, 0x4b, 0x4c, 0x4d, 0x47, 0x48, 0x49, 0x3b, /* p3, p4, p5, p6, p7, p8, p9, F1*/ + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, /* F2, F3, F4, F5, F6, F7, F8, F9*/ + 0x44, 0x57, 0x58, 0x01, 0x29, 0x0c, 0x0d, 0x0e, /*F10, F11, F12, ESC, `ª, -_, =+, backspace*/ + 0x0f, 0x1a, 0x1b, 0x1c, 0x27, 0x28, 0x2b, 0x56, /*TAB, [{, ]}, ENT, ;:, '@, \|, #~*/ + 0x33, 0x34, 0x35, 0x39, 0xd2, 0xd3, 0xc7, 0xcf, /* ,<, .>, /?, SPC, INS, DEL, HOME, END*/ + 0xc9, 0xd1, 0xcb, 0xcd, 0xc8, 0xd0, 0xb5, 0x37, /*PGU, PGD, LFT, RHT, UP, DN, /, * */ + 0x4a, 0x4e, 0x53, 0x9c, 0xff, -1, -1, -1, /* p-, p+, pDL, pEN, psc, pse, abnt, yen*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*kana, convert, noconvert, at, circumflex, colon2, kanji, pad equals*/ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 0x2a, 0x36, 0x1d, 0x9d, 0x38, /*, , lshift, rshift, lctrl, rctrl, alt*/ + 0xb8, 0xdb, 0xdc, 0xdd, 0x46, 0x45, 0x3a, -1 /*altgr, lwin, rwin, menu, scrlock, numlock, capslock*/ +}; + +void keyboard_init() +{ + install_keyboard(); +} + +void keyboard_close() +{ +} + +void keyboard_poll_host() +{ + int c; + + for (c = 0; c < 128; c++) + { + int key_idx = key_convert[c]; + if (key_idx == -1) + continue; + + if (key[c] != pcem_key[key_idx]) + pcem_key[key_idx] = key[c]; + } +} diff --git a/src/allegro-main.c b/src/allegro-main.c new file mode 100644 index 000000000..cf8407925 --- /dev/null +++ b/src/allegro-main.c @@ -0,0 +1,169 @@ +#include "allegro-main.h" +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "nvr.h" +#include "video.h" + +#undef printf + +int mousecapture = 0; +int quited = 0; +int winsizex = -1, winsizey = -1; + +int romspresent[ROM_MAX]; +int gfx_present[GFX_MAX]; + +void updatewindowsize(int x, int y) +{ + if (x < 128) + x = 128; + if (y < 128) + y = 128; + if (winsizex != x || winsizey != y) + { + winsizex = x; + winsizey = y; + allegro_video_update_size(x, y); + } +} + +void startblit() +{ +} + +void endblit() +{ +} + +static int ticks = 0; +static void timer_rout() +{ + ticks++; +} + +uint64_t timer_freq; +uint64_t timer_read() +{ + return 0; +} + +int main(int argc, char *argv[]) +{ + int frames = 0; + int c, d; + allegro_init(); + allegro_video_init(); + install_timer(); + install_int_ex(timer_rout, BPS_TO_TIMER(100)); + install_int_ex(onesec, BPS_TO_TIMER(1)); + midi_init(); + + initpc(argc, argv); + + d = romset; + for (c = 0; c < ROM_MAX; c++) + { + romset = c; + romspresent[c] = loadbios(); + pclog("romset %i - %i\n", c, romspresent[c]); + } + + for (c = 0; c < ROM_MAX; c++) + { + if (romspresent[c]) + break; + } + if (c == ROM_MAX) + { + printf("No ROMs present!\nYou must have at least one romset to use PCem."); + return 0; + } + + romset=d; + c=loadbios(); + + if (!c) + { + if (romset != -1) + printf("Configured romset not available.\nDefaulting to available romset."); + for (c = 0; c < ROM_MAX; c++) + { + if (romspresent[c]) + { + romset = c; + model = model_getmodel(romset); + saveconfig(); + resetpchard(); + break; + } + } + } + + for (c = 0; c < GFX_MAX; c++) + gfx_present[c] = video_card_available(video_old_to_new(c)); + + if (!video_card_available(video_old_to_new(gfxcard))) + { + if (gfxcard) printf("Configured video BIOS not available.\nDefaulting to available romset."); + for (c = GFX_MAX-1; c >= 0; c--) + { + if (gfx_present[c]) + { + gfxcard = c; + saveconfig(); + resetpchard(); + break; + } + } + } + + resetpchard(); + + ticks = 0; + while (!quited) + { + if (ticks) + { + ticks--; + runpc(); + frames++; + if (frames >= 200 && nvr_dosave) + { + frames = 0; + nvr_dosave = 0; + savenvr(); + } + } + else + rest(1); + + if (ticks > 10) + ticks = 0; + + if ((mouse_b & 1) && !mousecapture) + mousecapture = 1; + + if (((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_END]) || (mouse_b & 4)) + mousecapture = 0; + + if ((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_ALT] && key[KEY_PGDN]) + { + int old_winsizex = winsizex, old_winsizey = winsizey; + if (winsizex < 512 || winsizey < 350) + updatewindowsize(512, 350); + gui_enter(); + if (old_winsizex < 512 || old_winsizey < 350) + updatewindowsize(old_winsizex, old_winsizey); + ticks = 0; + } + } + + closepc(); + + midi_close(); + + return 0; +} + +END_OF_MAIN(); diff --git a/src/allegro-main.h b/src/allegro-main.h new file mode 100644 index 000000000..d5889a90d --- /dev/null +++ b/src/allegro-main.h @@ -0,0 +1,19 @@ +#define getr8 allegro_getr8 +#define setr8 allegro_setr8 +#define get_filename allegro_get_filename +#define append_filename allegro_append_filename +#define put_backslash allegro_put_backslash +#define get_extension allegro_get_extension +#define GFX_VGA allegro_GFX_VGA +#define MAX_JOYSTICKS allegro_MAX_JOYSTICKS + +#include + +#undef MAX_JOYSTICKS +#undef GFX_VGA +#undef getr8 +#undef setr8 +#undef get_filename +#undef append_filename +#undef put_backslash +#undef get_extension diff --git a/src/allegro-midi.c b/src/allegro-midi.c new file mode 100644 index 000000000..361e491d6 --- /dev/null +++ b/src/allegro-midi.c @@ -0,0 +1,45 @@ +#include "allegro-main.h" +#include "ibm.h" +#include "plat-midi.h" + +//#define USE_ALLEGRO_MIDI + +void midi_init() +{ +#ifdef USE_ALLEGRO_MIDI + install_sound(DIGI_NONE, MIDI_AUTODETECT, NULL); +#endif +} + +void midi_close() +{ +#ifdef USE_ALLEGRO_MIDI + remove_sound(); +#endif +} + +static int midi_cmd_pos, midi_len; +static uint8_t midi_command[3]; +static int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 0}; + +void midi_write(uint8_t val) +{ + if (val & 0x80) + { + midi_cmd_pos = 0; + midi_len = midi_lengths[(val >> 4) & 7]; + midi_command[0] = midi_command[1] = midi_command[2] = 0; + } + + if (midi_len && midi_cmd_pos < 3) + { + midi_command[midi_cmd_pos] = val; + + midi_cmd_pos++; + +#ifdef USE_ALLEGRO_MIDI + if (midi_cmd_pos == midi_len) + midi_out(midi_command, midi_len); +#endif + } +} diff --git a/src/allegro-mouse.c b/src/allegro-mouse.c new file mode 100644 index 000000000..214a802a6 --- /dev/null +++ b/src/allegro-mouse.c @@ -0,0 +1,31 @@ +#include "allegro-main.h" +#include "plat-mouse.h" + +int mouse_buttons; + +void mouse_init() +{ + install_mouse(); +} + +void mouse_close() +{ +} + +void mouse_poll_host() +{ + //poll_mouse(); + mouse_buttons = mouse_b; +} + +void mouse_get_mickeys(int *x, int *y) +{ + if (mousecapture) + { + get_mouse_mickeys(x, y); +// position_mouse(64, 64); + } + else + *x = *y = 0; +} + diff --git a/src/allegro-video.c b/src/allegro-video.c new file mode 100644 index 000000000..b7612f0b8 --- /dev/null +++ b/src/allegro-video.c @@ -0,0 +1,127 @@ +#include "allegro-main.h" +#include "ibm.h" +#include "video.h" + +#include "allegro-video.h" + +static PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +static void allegro_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void allegro_blit_memtoscreen_8(int x, int y, int w, int h); +static BITMAP *buffer32_vscale; +void allegro_video_init() +{ + int c; + + set_color_depth(32); + set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); + video_blit_memtoscreen = allegro_blit_memtoscreen; + video_blit_memtoscreen_8 = allegro_blit_memtoscreen_8; + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + buffer32_vscale = create_bitmap(2048, 2048); +} + +void allegro_video_close() +{ + destroy_bitmap(buffer32_vscale); +} + +void allegro_video_update_size(int x, int y) +{ + if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, x, y, 0, 0)) + fatal("Failed to set gfx mode %i,%i : %s\n", x, y, allegro_error); +} + +static void allegro_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + if (h < winsizey) + { + int yy; + + for (yy = y+y1; yy < y+y2; yy++) + { + if (yy >= 0) + { + memcpy(&((uint32_t *)buffer32_vscale->line[yy*2])[x], &((uint32_t *)buffer32->line[yy])[x], w*4); + memcpy(&((uint32_t *)buffer32_vscale->line[(yy*2)+1])[x], &((uint32_t *)buffer32->line[yy])[x], w*4); + } + } + + blit(buffer32_vscale, screen, x, (y+y1)*2, 0, y1, w, (y2-y1)*2); + } + else + blit(buffer32, screen, x, y+y1, 0, y1, w, y2-y1); +} + +static void allegro_blit_memtoscreen_8(int x, int y, int w, int h) +{ + int xx, yy; + int line_double = (winsizey > h) ? 1 : 0; + + if (y < 0) + { + h += y; + y = 0; + } + + for (yy = y; yy < y+h; yy++) + { + int dy = line_double ? yy*2 : yy; + if (dy < buffer->h) + { + if (line_double) + { + for (xx = x; xx < x+w; xx++) + { + ((uint32_t *)buffer32->line[dy])[xx] = + ((uint32_t *)buffer32->line[dy + 1])[xx] = pal_lookup[buffer->line[yy][xx]]; + } + } + else + { + for (xx = x; xx < x+w; xx++) + ((uint32_t *)buffer32->line[dy])[xx] = pal_lookup[buffer->line[yy][xx]]; + } + } + } + + if (readflash) + { + if (line_double) + rectfill(buffer32, x+SCREEN_W-40, y*2+8, SCREEN_W-8, y*2+14, makecol(255, 255, 255)); + else + rectfill(buffer32, x+SCREEN_W-40, y+8, SCREEN_W-8, y+14, makecol(255, 255, 255)); + readflash = 0; + } + + if (line_double) + blit(buffer32, screen, x, y*2, 0, 0, w, h*2); + else + blit(buffer32, screen, x, y, 0, 0, w, h); +} diff --git a/src/allegro-video.h b/src/allegro-video.h new file mode 100644 index 000000000..76ce4eabc --- /dev/null +++ b/src/allegro-video.h @@ -0,0 +1,3 @@ +void allegro_video_init(); +void allegro_video_close(); +void allegro_video_update_size(int x, int y); diff --git a/src/amstrad.c b/src/amstrad.c new file mode 100644 index 000000000..505eb07c2 --- /dev/null +++ b/src/amstrad.c @@ -0,0 +1,83 @@ +#include "ibm.h" +#include "io.h" +#include "keyboard.h" +#include "lpt.h" +#include "mouse.h" + +#include "amstrad.h" + +static uint8_t amstrad_dead; + +uint8_t amstrad_read(uint16_t port, void *priv) +{ + pclog("amstrad_read : %04X\n",port); + switch (port) + { + case 0x379: + return 7 | readdacfifo(); + case 0x37a: + if (romset == ROM_PC1512) return 0x20; + if (romset == ROM_PC200) return 0x80; + return 0; + case 0xdead: + return amstrad_dead; + } + return 0xff; +} + +void amstrad_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port) + { + case 0xdead: + amstrad_dead = val; + break; + } +} + +static uint8_t mousex,mousey; + +void amstrad_mouse_write(uint16_t addr, uint8_t val, void *priv) +{ +// pclog("Write mouse %04X %02X %04X:%04X\n", addr, val, CS, pc); + if (addr==0x78) mousex=0; + else mousey=0; +} + +uint8_t amstrad_mouse_read(uint16_t addr, void *priv) +{ +// printf("Read mouse %04X %04X:%04X %02X\n", addr, CS, pc, (addr == 0x78) ? mousex : mousey); + if (addr==0x78) return mousex; + return mousey; +} + +static int oldb = 0; + +void amstrad_mouse_poll(int x, int y, int b) +{ + mousex += x; + mousey -= y; + + if ((b & 1) && !(oldb & 1)) + keyboard_send(0x7e); + if ((b & 2) && !(oldb & 2)) + keyboard_send(0x7d); + if (!(b & 1) && (oldb & 1)) + keyboard_send(0xfe); + if (!(b & 2) && (oldb & 2)) + keyboard_send(0xfd); + + oldb = b; +} + +void amstrad_init() +{ + lpt2_remove_ams(); + + io_sethandler(0x0078, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL, NULL); + io_sethandler(0x007a, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL, NULL); + io_sethandler(0x0379, 0x0002, amstrad_read, NULL, NULL, NULL, NULL, NULL, NULL); + io_sethandler(0xdead, 0x0001, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL, NULL); + + mouse_poll = amstrad_mouse_poll; +} diff --git a/src/amstrad.h b/src/amstrad.h new file mode 100644 index 000000000..5fac1a524 --- /dev/null +++ b/src/amstrad.h @@ -0,0 +1,2 @@ +void amstrad_init(); + diff --git a/src/bswap.h b/src/bswap.h new file mode 100644 index 000000000..070a40a89 --- /dev/null +++ b/src/bswap.h @@ -0,0 +1,202 @@ +#ifndef BSWAP_H +#define BSWAP_H + +//#include "config-host.h" + +#include + +#ifdef HAVE_BYTESWAP_H +#include +#else + +#define bswap_16(x) \ +({ \ + uint16_t __x = (x); \ + ((uint16_t)( \ + (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ +}) + +#define bswap_32(x) \ +({ \ + uint32_t __x = (x); \ + ((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ +}) + +#define bswap_64(x) \ +({ \ + uint64_t __x = (x); \ + ((uint64_t)( \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ +}) + +#endif /* !HAVE_BYTESWAP_H */ + +static inline uint16_t bswap16(uint16_t x) +{ + return bswap_16(x); +} + +static inline uint32_t bswap32(uint32_t x) +{ + return bswap_32(x); +} + +static inline uint64_t bswap64(uint64_t x) +{ + return bswap_64(x); +} + +static inline void bswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static inline void bswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static inline void bswap64s(uint64_t *s) +{ + *s = bswap64(*s); +} + +#if defined(WORDS_BIGENDIAN) +#define be_bswap(v, size) (v) +#define le_bswap(v, size) bswap ## size(v) +#define be_bswaps(v, size) +#define le_bswaps(p, size) *p = bswap ## size(*p); +#else +#define le_bswap(v, size) (v) +#define be_bswap(v, size) bswap ## size(v) +#define le_bswaps(v, size) +#define be_bswaps(p, size) *p = bswap ## size(*p); +#endif + +#define CPU_CONVERT(endian, size, type)\ +static inline type endian ## size ## _to_cpu(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static inline type cpu_to_ ## endian ## size(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static inline void endian ## size ## _to_cpus(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static inline void cpu_to_ ## endian ## size ## s(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static inline type endian ## size ## _to_cpup(const type *p)\ +{\ + return endian ## size ## _to_cpu(*p);\ +}\ +\ +static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\ +{\ + *p = cpu_to_ ## endian ## size(v);\ +} + +CPU_CONVERT(be, 16, uint16_t) +CPU_CONVERT(be, 32, uint32_t) +CPU_CONVERT(be, 64, uint64_t) + +CPU_CONVERT(le, 16, uint16_t) +CPU_CONVERT(le, 32, uint32_t) +CPU_CONVERT(le, 64, uint64_t) + +/* unaligned versions (optimized for frequent unaligned accesses)*/ + +#if defined(__i386__) || defined(__powerpc__) + +#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) +#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) +#define le16_to_cpupu(p) le16_to_cpup(p) +#define le32_to_cpupu(p) le32_to_cpup(p) + +#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) +#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) + +#else + +static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v; + p1[1] = v >> 8; +} + +static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v; + p1[1] = v >> 8; + p1[2] = v >> 16; + p1[3] = v >> 24; +} + +static inline uint16_t le16_to_cpupu(const uint16_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8); +} + +static inline uint32_t le32_to_cpupu(const uint32_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); +} + +static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 8; + p1[1] = v; +} + +static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 24; + p1[1] = v >> 16; + p1[2] = v >> 8; + p1[3] = v; +} + +#endif + +#ifdef WORDS_BIGENDIAN +#define cpu_to_32wu cpu_to_be32wu +#else +#define cpu_to_32wu cpu_to_le32wu +#endif + +#undef le_bswap +#undef be_bswap +#undef le_bswaps +#undef be_bswaps + +#endif /* BSWAP_H */ diff --git a/src/cdrom-ioctl-linux.c b/src/cdrom-ioctl-linux.c new file mode 100644 index 000000000..60d3ae42d --- /dev/null +++ b/src/cdrom-ioctl-linux.c @@ -0,0 +1,724 @@ +/*Linux CD-ROM support via IOCTL*/ + +#include +#include +#include +#include +#include "ibm.h" +#include "ide.h" +#include "cdrom-ioctl.h" + +static ATAPI ioctl_atapi; + +static uint32_t last_block = 0; +static uint32_t cdrom_capacity = 0; +static int ioctl_inited = 0; +static char ioctl_path[8]; +static int tocvalid = 0; +static struct cdrom_tocentry toc[100]; +static int first_track, last_track; + +int old_cdrom_drive; + +#define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150) + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +static int ioctl_cd_state = CD_STOPPED; +static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0; +#define BUF_SIZE 32768 +static int16_t cd_buffer[BUF_SIZE]; +static int cd_buflen = 0; +void ioctl_audio_callback(int16_t *output, int len) +{ + int fd; + struct cdrom_read_audio read_audio; + +// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount()); + if (ioctl_cd_state != CD_PLAYING) + { + memset(output, 0, len * 2); + return; + } + fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + { + memset(output, 0, len * 2); + return; + } + + while (cd_buflen < len) + { + if (ioctl_cd_pos < ioctl_cd_end) + { + read_audio.addr.lba = ioctl_cd_pos - 150; + read_audio.addr_format = CDROM_LBA; + read_audio.nframes = 1; + read_audio.buf = (__u8 *)&cd_buffer[cd_buflen]; + + if (ioctl(fd, CDROMREADAUDIO, &read_audio) < 0) + { +// pclog("DeviceIoControl returned false\n"); + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + else + { +// pclog("DeviceIoControl returned true\n"); + ioctl_cd_pos++; + cd_buflen += (2352 / 2); + } + } + else + { + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + } + close(fd); + memcpy(output, cd_buffer, len * 2); +// for (c = 0; c < BUF_SIZE - len; c++) +// cd_buffer[c] = cd_buffer[c + cd_buflen]; + memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2); + cd_buflen -= len; +// pclog("Done %i\n", GetTickCount()); +} + +void ioctl_audio_stop() +{ + ioctl_cd_state = CD_STOPPED; +} + +static int get_track_nr(uint32_t pos) +{ + int c; + int track = 0; + + if (!tocvalid) + return 0; + + for (c = first_track; c < last_track; c++) + { + uint32_t track_address = toc[c].cdte_addr.msf.frame + + (toc[c].cdte_addr.msf.second * 75) + + (toc[c].cdte_addr.msf.minute * 75 * 60); +//pclog("get_track_nr: track=%i pos=%x track_address=%x\n", c, pos, track_address); + if (track_address <= pos) + track = c; + } + return track; +} + +static int is_track_audio(uint32_t pos) +{ + int c; + int control = 0; + + if (!tocvalid) + return 0; + + for (c = first_track; c < last_track; c++) + { + uint32_t track_address = toc[c].cdte_addr.msf.frame + + (toc[c].cdte_addr.msf.second * 75) + + (toc[c].cdte_addr.msf.minute * 75 * 60); +//pclog("get_track_nr: track=%i pos=%x track_address=%x\n", c, pos, track_address); + if (track_address <= pos) + control = toc[c].cdte_ctrl; + } + return (control & 4) ? 0 : 1; +} + +static int ioctl_is_track_audio(uint32_t pos, int ismsf) +{ + if (ismsf) + { + int m = (pos >> 16) & 0xff; + int s = (pos >> 8) & 0xff; + int f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + } + return is_track_audio(pos); +} + +static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ +// pclog("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf) + { + pos = (pos & 0xff) + (((pos >> 8) & 0xff) * 75) + (((pos >> 16) & 0xff) * 75 * 60); + len = (len & 0xff) + (((len >> 8) & 0xff) * 75) + (((len >> 16) & 0xff) * 75 * 60); +// pclog("MSF - pos = %08X len = %08X\n", pos, len); + } + else + len += pos; + ioctl_cd_pos = pos;// + 150; + ioctl_cd_end = pos+len;// + 150; + ioctl_cd_state = CD_PLAYING; + if (ioctl_cd_pos < 150) + ioctl_cd_pos = 150; +// pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, 0, len); +} + +static void ioctl_pause(void) +{ + if (ioctl_cd_state == CD_PLAYING) + ioctl_cd_state = CD_PAUSED; +} + +static void ioctl_resume(void) +{ + if (ioctl_cd_state == CD_PAUSED) + ioctl_cd_state = CD_PLAYING; +} + +static void ioctl_stop(void) +{ + ioctl_cd_state = CD_STOPPED; +} + +static void ioctl_seek(uint32_t pos) +{ +// pclog("Seek %08X\n", pos); + ioctl_cd_pos = pos; + ioctl_cd_state = CD_STOPPED; +} + +static int read_toc(int fd, struct cdrom_tocentry *btoc) +{ + struct cdrom_tochdr toc_hdr; + int track, err; +//pclog("read_toc\n"); + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + pclog("read_toc: CDROMREADTOCHDR failed\n"); + return 0; + } + + first_track = toc_hdr.cdth_trk0; + last_track = toc_hdr.cdth_trk1; +//pclog("read_toc: first_track=%i last_track=%i\n", first_track, last_track); + memset(btoc, 0, sizeof(btoc)); + + for (track = toc_hdr.cdth_trk0; track <= toc_hdr.cdth_trk1; track++) + { + btoc[track].cdte_track = track; + btoc[track].cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &btoc[track]); + if (err == -1) + { +// pclog("read_toc: CDROMREADTOCENTRY failed on track %i\n", track); + return 0; + } +// pclog("read_toc: Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", track, toc[track].cdte_track, toc[track].cdte_ctrl, toc[track].cdte_adr, 0, toc[track].cdte_addr.msf.minute, toc[track].cdte_addr.msf.second, toc[track].cdte_addr.msf.frame); + } + return 1; +} + +static int ioctl_ready(void) +{ + long size; + int temp; + struct cdrom_tochdr toc_hdr; + struct cdrom_tocentry toc_entry; + int err; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + close(fd); + return 0; + } +// pclog("CDROMREADTOCHDR: start track=%i end track=%i\n", toc_hdr.cdth_trk0, toc_hdr.cdth_trk1); + toc_entry.cdte_track = toc_hdr.cdth_trk1; + toc_entry.cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &toc_entry); + if (err == -1) + { + close(fd); + return 0; + } +// pclog("CDROMREADTOCENTRY: addr=%02i:%02i:%02i\n", toc_entry.cdte_addr.msf.minute, toc_entry.cdte_addr.msf.second, toc_entry.cdte_addr.msf.frame); + if ((toc_entry.cdte_addr.msf.minute != toc[toc_hdr.cdth_trk1].cdte_addr.msf.minute) || + (toc_entry.cdte_addr.msf.second != toc[toc_hdr.cdth_trk1].cdte_addr.msf.second) || + (toc_entry.cdte_addr.msf.frame != toc[toc_hdr.cdth_trk1].cdte_addr.msf.frame ) || + !tocvalid) + { + int track; + ioctl_cd_state = CD_STOPPED; + + tocvalid = read_toc(fd, toc); + close(fd); + return 1; + } + close(fd); + return 1; +} + +static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, int single) +{ + int c; + int lb = 0; + int tv = 0; + struct cdrom_tocentry lbtoc[100]; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + ioctl_cd_state = CD_STOPPED; + + tv = read_toc(fd, lbtoc); + + close(fd); + + if (!tv) + return 0; + + last_block = 0; + for (c = 0; c <= last_track; c++) + { + uint32_t address; + address = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + if (address > last_block) + lb = address; + } + return lb; +} + +static int ioctl_medium_changed(void) +{ + long size; + int temp; + struct cdrom_tochdr toc_hdr; + struct cdrom_tocentry toc_entry; + int err; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + close(fd); + return 0; + } + toc_entry.cdte_track = toc_hdr.cdth_trk1; + toc_entry.cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &toc_entry); + if (err == -1) + { + close(fd); + return 0; + } +// pclog("CDROMREADTOCENTRY: addr=%02i:%02i:%02i\n", toc_entry.cdte_addr.msf.minute, toc_entry.cdte_addr.msf.second, toc_entry.cdte_addr.msf.frame); + if ((toc_entry.cdte_addr.msf.minute != toc[toc_hdr.cdth_trk1].cdte_addr.msf.minute) || + (toc_entry.cdte_addr.msf.second != toc[toc_hdr.cdth_trk1].cdte_addr.msf.second) || + (toc_entry.cdte_addr.msf.frame != toc[toc_hdr.cdth_trk1].cdte_addr.msf.frame )) + { + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); + return 1; + } + return 0; +} + +static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) +{ + struct cdrom_subchnl sub; + uint32_t cdpos = ioctl_cd_pos; + int track = get_track_nr(cdpos); + uint32_t track_address = toc[track].cdte_addr.msf.frame + + (toc[track].cdte_addr.msf.second * 75) + + (toc[track].cdte_addr.msf.minute * 75 * 60); + long size; + int pos=0; + int err; + uint8_t ret; +//pclog("ioctl_getsubchannel: cdpos=%x track_address=%x track=%i\n", cdpos, track_address, track); + if (ioctl_cd_state == CD_PLAYING) + ret = 0x11; + else if (ioctl_cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + + b[pos++] = (toc[track].cdte_adr << 4) | toc[track].cdte_ctrl; + b[pos++] = track; + b[pos++] = 0; + + if (msf) + { + uint32_t dat = cdpos; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + dat = cdpos - track_address; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + } + else + { + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + cdpos -= track_address; + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + } + + return ret; +} + +static void ioctl_eject(void) +{ + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return; + + ioctl(fd, CDROMEJECT); + + close(fd); +} + +static void ioctl_load(void) +{ + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return; + + ioctl(fd, CDROMEJECT); + + close(fd); + + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); +} + +static void ioctl_readsector(uint8_t *b, int sector) +{ + int cdrom = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + if (cdrom <= 0) + return; + lseek(cdrom, sector*2048, SEEK_SET); + read(cdrom, b, 2048); + close(cdrom); +} + +union +{ + struct cdrom_msf *msf; + char b[CD_FRAMESIZE_RAW]; +} raw_read_params; + +static int lba_to_msf(int lba) +{ + return (((lba / 75) / 60) << 16) + (((lba / 75) % 60) << 8) + (lba % 75); +} + +static void ioctl_readsector_raw(uint8_t *b, int sector) +{ + int err; + int imsf = lba_to_msf(sector); + int cdrom = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (cdrom <= 0) + return; + + raw_read_params.msf = malloc(sizeof(struct cdrom_msf)); + raw_read_params.msf->cdmsf_frame0 = imsf & 0xff; + raw_read_params.msf->cdmsf_sec0 = (imsf >> 8) & 0xff; + raw_read_params.msf->cdmsf_min0 = (imsf >> 16) & 0xff; + + /* This will read the actual raw sectors from the disc. */ + err = ioctl(cdrom, CDROMREADRAW, (void *) &raw_read_params); + if (err == -1) + { + pclog("read_toc: CDROMREADTOCHDR failed\n"); + return; + } + + memcpy(b, raw_read_params.b, 2352); + + close(cdrom); + + free(raw_read_params.msf); +} + +static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + long size; + int c,d; + uint32_t temp; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + ioctl_cd_state = CD_STOPPED; + + tocvalid = read_toc(fd, toc); + + close(fd); + + if (!tocvalid) + return 4; + +// pclog("Read TOC done! %i\n",single); + b[2] = first_track; + b[3] = last_track; + d = 0; +//pclog("Read TOC starttrack=%i\n", starttrack); + for (c = 1; c <= last_track; c++) + { + if (toc[c].cdte_track >= starttrack) + { + d = c; + break; + } + } + b[2] = toc[c].cdte_track; + last_block = 0; + for (c = d; c <= last_track; c++) + { + uint32_t address; + if ((len + 8) > maxlen) + break; +// pclog("Len %i max %i Track %02X - %02X %02X %02i:%02i:%02i %08X\n",len,maxlen,toc[c].cdte_track,toc[c].cdte_adr,toc[c].cdte_ctrl,toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame,MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame)); + b[len++] = 0; /*Reserved*/ + b[len++] = (toc[c].cdte_adr << 4) | toc[c].cdte_ctrl; + b[len++] = toc[c].cdte_track; + b[len++] = 0; /*Reserved*/ + address = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + if (address > last_block) + last_block = address; + + if (msf) + { + b[len++] = 0; + b[len++] = toc[c].cdte_addr.msf.minute; + b[len++] = toc[c].cdte_addr.msf.second; + b[len++] = toc[c].cdte_addr.msf.frame; + } + else + { + temp = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + if (single) + break; + } + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); +/* pclog("Table of Contents (%i bytes) : \n", size); + pclog("First track - %02X\n", first_track); + pclog("Last track - %02X\n", last_track); + for (c = 0; c <= last_track; c++) + pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", c, toc[c].cdte_track, toc[c].cdte_ctrl, toc[c].cdte_adr, 0, toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + for (c = 0;c <= last_track; c++) + pclog("Track %02X - number %02X control %02X adr %02X address %06X\n", c, toc[c].cdte_track, toc[c].cdte_ctrl, toc[c].cdte_adr, MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame));*/ + return len; +} + +static int ioctl_readtoc_session(unsigned char *b, int msf, int maxlen) +{ + struct cdrom_multisession session; + int len = 4; + int err; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + session.addr_format = CDROM_MSF; + err = ioctl(fd, CDROMMULTISESSION, &session); + + if (err == -1) + { + close(fd); + return 0; + } + + b[2] = 0; + b[3] = 0; + b[len++] = 0; /*Reserved*/ + b[len++] = (toc[0].cdte_adr << 4) | toc[0].cdte_ctrl; + b[len++] = toc[0].cdte_track; + b[len++] = 0; /*Reserved*/ + if (msf) + { + b[len++] = 0; + b[len++] = session.addr.msf.minute; + b[len++] = session.addr.msf.second; + b[len++] = session.addr.msf.frame; + } + else + { + uint32_t temp = MSFtoLBA(session.addr.msf.minute, session.addr.msf.second, session.addr.msf.frame); + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + return len; +} + +static int ioctl_readtoc_raw(unsigned char *b, int maxlen) +{ + struct cdrom_tochdr toc_hdr; + struct cdrom_tocentry toc2[100]; + int track, err; + int len = 4; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); +//pclog("read_toc\n"); + if (fd <= 0) + return 0; + + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + pclog("read_toc: CDROMREADTOCHDR failed\n"); + return 0; + } + + b[2] = toc_hdr.cdth_trk0; + b[3] = toc_hdr.cdth_trk1; + + //pclog("read_toc: first_track=%i last_track=%i\n", first_track, last_track); + memset(toc, 0, sizeof(toc)); + + for (track = toc_hdr.cdth_trk0; track <= toc_hdr.cdth_trk1; track++) + { + if ((len + 11) > maxlen) + { + pclog("ioctl_readtocraw: This iteration would fill the buffer beyond the bounds, aborting...\n"); + close(fd); + return len; + } + + toc2[track].cdte_track = track; + toc2[track].cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &toc2[track]); + if (err == -1) + { +// pclog("read_toc: CDROMREADTOCENTRY failed on track %i\n", track); + close(fd); + return 0; + } +// pclog("read_toc: Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", track, toc[track].cdte_track, toc[track].cdte_ctrl, toc[track].cdte_adr, 0, toc[track].cdte_addr.msf.minute, toc[track].cdte_addr.msf.second, toc[track].cdte_addr.msf.frame); + + b[len++] = toc2[track].cdte_track; + b[len++]= (toc2[track].cdte_adr << 4) | toc[track].cdte_ctrl; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++] = toc2[track].cdte_addr.msf.minute; + b[len++] = toc2[track].cdte_addr.msf.second; + b[len++] = toc2[track].cdte_addr.msf.frame; + } + close(fd); + return len; +} + +static uint32_t ioctl_size() +{ + return cdrom_capacity; +} + +static int ioctl_status() +{ + if (!(ioctl_ready) && (cdrom_drive <= 0)) return CD_STATUS_EMPTY; + + switch(ioctl_cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + return CD_STATUS_STOPPED; + } +} +void ioctl_reset() +{ + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); +//pclog("ioctl_reset: fd=%i\n", fd); + tocvalid = 0; + + if (fd <= 0) + return; + + tocvalid = read_toc(fd, toc); + + close(fd); +} + +int ioctl_open(char d) +{ + atapi=&ioctl_atapi; + return 0; +} + +void ioctl_close(void) +{ +} + +static void ioctl_exit(void) +{ + ioctl_stop(); + ioctl_inited = 0; + tocvalid=0; +} + +static ATAPI ioctl_atapi= +{ + ioctl_ready, + ioctl_medium_changed, + ioctl_readtoc, + ioctl_readtoc_session, + ioctl_readtoc_raw, + ioctl_getcurrentsubchannel, + ioctl_readsector, + ioctl_readsector_raw, + ioctl_playaudio, + ioctl_seek, + ioctl_load, + ioctl_eject, + ioctl_pause, + ioctl_resume, + ioctl_size, + ioctl_status, + ioctl_is_track_audio, + ioctl_stop, + ioctl_exit +}; diff --git a/src/cdrom-ioctl.c b/src/cdrom-ioctl.c new file mode 100644 index 000000000..a7642f5cb --- /dev/null +++ b/src/cdrom-ioctl.c @@ -0,0 +1,747 @@ +/*Win32 CD-ROM support via IOCTL*/ + +#include +#include +#include "ntddcdrm.h" +#include "ibm.h" +#include "ide.h" +#include "cdrom-ioctl.h" + +int cdrom_drive; +int old_cdrom_drive; + +static ATAPI ioctl_atapi; + +static uint32_t last_block = 0; +static uint32_t cdrom_capacity = 0; +static int ioctl_inited = 0; +static char ioctl_path[8]; +void ioctl_close(void); +static HANDLE hIOCTL; +static CDROM_TOC toc; +static int tocvalid = 0; + +// #define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150) +/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: + there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start + of the audio while audio still plays. With an absolute conversion, the counter is fine. */ +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +static int ioctl_cd_state = CD_STOPPED; +static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0; + +#define BUF_SIZE 32768 +static int16_t cd_buffer[BUF_SIZE]; +static int cd_buflen = 0; +void ioctl_audio_callback(int16_t *output, int len) +{ + RAW_READ_INFO in; + DWORD count; + +// return; +// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount()); + if (ioctl_cd_state != CD_PLAYING) + { + memset(output, 0, len * 2); + return; + } + while (cd_buflen < len) + { + if (ioctl_cd_pos < ioctl_cd_end) + { + in.DiskOffset.LowPart = (ioctl_cd_pos - 150) * 2048; + in.DiskOffset.HighPart = 0; + in.SectorCount = 1; + in.TrackMode = CDDA; + ioctl_open(0); +// pclog("Read to %i\n", cd_buflen); + if (!DeviceIoControl(hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &cd_buffer[cd_buflen], 2352, &count, NULL)) + { +// pclog("DeviceIoControl returned false\n"); + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + else + { +// pclog("DeviceIoControl returned true\n"); + ioctl_cd_pos++; + cd_buflen += (2352 / 2); + } + ioctl_close(); + } + else + { + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + } + memcpy(output, cd_buffer, len * 2); +// for (c = 0; c < BUF_SIZE - len; c++) +// cd_buffer[c] = cd_buffer[c + cd_buflen]; + memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2); + cd_buflen -= len; +// pclog("Done %i\n", GetTickCount()); +} + +void ioctl_audio_stop() +{ + ioctl_cd_state = CD_STOPPED; +} + +static int get_track_nr(uint32_t pos) +{ + int c; + int track = 0; + + if (!tocvalid) + return 0; + + for (c = toc.FirstTrack; c < toc.LastTrack; c++) + { + uint32_t track_address = toc.TrackData[c].Address[3] + + (toc.TrackData[c].Address[2] * 75) + + (toc.TrackData[c].Address[1] * 75 * 60); + + if (track_address <= pos) + track = c; + } + return track; +} + +static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ + if (!cdrom_drive) return; + pclog("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf) + { + int m = (pos >> 16) & 0xff; + int s = (pos >> 8) & 0xff; + int f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f); + pclog("MSF - pos = %08X len = %08X\n", pos, len); + } + else + len += pos; + ioctl_cd_pos = pos;// + 150; + ioctl_cd_end = len;// + 150; + if (ioctl_cd_pos < 150) + { + /* Adjust because the host expects a minimum adjusted LBA of 0 which is equivalent to an absolute LBA of 150. */ + ioctl_cd_pos = 150; + } + ioctl_cd_state = CD_PLAYING; + pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len); +/* CDROM_PLAY_AUDIO_MSF msf; + long size; + BOOL b; + if (ismsf) + { + msf.StartingF=pos&0xFF; + msf.StartingS=(pos>>8)&0xFF; + msf.StartingM=(pos>>16)&0xFF; + msf.EndingF=len&0xFF; + msf.EndingS=(len>>8)&0xFF; + msf.EndingM=(len>>16)&0xFF; + } + else + { + msf.StartingF=(uint8_t)(addr%75); addr/=75; + msf.StartingS=(uint8_t)(addr%60); addr/=60; + msf.StartingM=(uint8_t)(addr); + addr=pos+len+150; + msf.EndingF=(uint8_t)(addr%75); addr/=75; + msf.EndingS=(uint8_t)(addr%60); addr/=60; + msf.EndingM=(uint8_t)(addr); + } + ioctl_open(0); + b = DeviceIoControl(hIOCTL,IOCTL_CDROM_PLAY_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL); + pclog("DeviceIoControl returns %i\n", (int) b); + ioctl_close();*/ +} + +static void ioctl_pause(void) +{ + if (!cdrom_drive) return; + if (ioctl_cd_state == CD_PLAYING) + ioctl_cd_state = CD_PAUSED; +// ioctl_open(0); +// DeviceIoControl(hIOCTL,IOCTL_CDROM_PAUSE_AUDIO,NULL,0,NULL,0,&size,NULL); +// ioctl_close(); +} + +static void ioctl_resume(void) +{ + if (!cdrom_drive) return; + if (ioctl_cd_state == CD_PAUSED) + ioctl_cd_state = CD_PLAYING; +// ioctl_open(0); +// DeviceIoControl(hIOCTL,IOCTL_CDROM_RESUME_AUDIO,NULL,0,NULL,0,&size,NULL); +// ioctl_close(); +} + +static void ioctl_stop(void) +{ + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; +// ioctl_open(0); +// DeviceIoControl(hIOCTL,IOCTL_CDROM_STOP_AUDIO,NULL,0,NULL,0,&size,NULL); +// ioctl_close(); +} + +static void ioctl_seek(uint32_t pos) +{ + if (!cdrom_drive) return; + // ioctl_cd_state = CD_STOPPED; + pclog("Seek %08X\n", pos); + ioctl_cd_pos = pos; + ioctl_cd_state = CD_STOPPED; +/* pos+=150; + CDROM_SEEK_AUDIO_MSF msf; + msf.F=(uint8_t)(pos%75); pos/=75; + msf.S=(uint8_t)(pos%60); pos/=60; + msf.M=(uint8_t)(pos); +// pclog("Seek to %02i:%02i:%02i\n",msf.M,msf.S,msf.F); + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_SEEK_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL); + ioctl_close();*/ +} + +static int ioctl_ready(void) +{ + long size; + int temp; + CDROM_TOC ltoc; +// pclog("Ready? %i\n",cdrom_drive); + if (!cdrom_drive) return 0; + ioctl_open(0); + temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,<oc,sizeof(ltoc),&size,NULL); + ioctl_close(); + if (!temp) + return 0; + //pclog("ioctl_ready(): Drive opened successfully\n"); + //if ((cdrom_drive != old_cdrom_drive)) pclog("Drive has changed\n"); + if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) || + (ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) || + (ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3]) || + !tocvalid || (cdrom_drive != old_cdrom_drive)) + { + //pclog("ioctl_ready(): Disc or drive changed\n"); + ioctl_cd_state = CD_STOPPED; + /* pclog("Not ready %02X %02X %02X %02X %02X %02X %i\n",ltoc.TrackData[ltoc.LastTrack].Address[1],ltoc.TrackData[ltoc.LastTrack].Address[2],ltoc.TrackData[ltoc.LastTrack].Address[3], + toc.TrackData[ltoc.LastTrack].Address[1], toc.TrackData[ltoc.LastTrack].Address[2], toc.TrackData[ltoc.LastTrack].Address[3],tocvalid);*/ + // atapi_discchanged(); +/* ioctl_open(0); + temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL); + ioctl_close();*/ + if (cdrom_drive != old_cdrom_drive) + old_cdrom_drive = cdrom_drive; + return 1; + } +// pclog("IOCTL says ready\n"); +// pclog("ioctl_ready(): All is good\n"); + return 1; +} + +static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + long size; + int c,d; + uint32_t temp; + CDROM_TOC lbtoc; + int lb=0; + if (!cdrom_drive) return 0; + ioctl_cd_state = CD_STOPPED; + pclog("ioctl_readtoc(): IOCtl state now CD_STOPPED\n"); + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&lbtoc,sizeof(lbtoc),&size,NULL); + ioctl_close(); + tocvalid=1; + for (c=d;c<=lbtoc.LastTrack;c++) + { + uint32_t address; + address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + if (address > lb) + lb = address; + } + return lb; +} + +static int ioctl_medium_changed(void) +{ + long size; + int temp; + CDROM_TOC ltoc; + if (!cdrom_drive) return 0; /* This will be handled by the not ready handler instead. */ + ioctl_open(0); + temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,<oc,sizeof(ltoc),&size,NULL); + ioctl_close(); + if (!temp) + return 0; /* Drive empty, a not ready handler matter, not disc change. */ + if (!tocvalid || (cdrom_drive != old_cdrom_drive)) + { + ioctl_cd_state = CD_STOPPED; + toc = ltoc; + tocvalid = 1; + if (cdrom_drive != old_cdrom_drive) + old_cdrom_drive = cdrom_drive; + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); + return 0; + } + if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) || + (ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) || + (ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3])) + { + ioctl_cd_state = CD_STOPPED; + toc = ltoc; + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); + return 1; /* TOC mismatches. */ + } + return 0; /* None of the above, return 0. */ +} + +static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) +{ + CDROM_SUB_Q_DATA_FORMAT insub; + SUB_Q_CHANNEL_DATA sub; + long size; + int pos=0; + if (!cdrom_drive) return 0; + + insub.Format = IOCTL_CDROM_CURRENT_POSITION; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL); + ioctl_close(); + + if (ioctl_cd_state == CD_PLAYING || ioctl_cd_state == CD_PAUSED) + { + uint32_t cdpos = ioctl_cd_pos; + int track = get_track_nr(cdpos); + uint32_t track_address = toc.TrackData[track].Address[3] + + (toc.TrackData[track].Address[2] * 75) + + (toc.TrackData[track].Address[1] * 75 * 60); + + b[pos++] = sub.CurrentPosition.Control; + b[pos++] = track + 1; + b[pos++] = sub.CurrentPosition.IndexNumber; + + if (msf) + { + uint32_t dat = cdpos; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + dat = cdpos - track_address; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + } + else + { + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + cdpos -= track_address; + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + } + + if (ioctl_cd_state == CD_PLAYING) return 0x11; + return 0x12; + } + + b[pos++]=sub.CurrentPosition.Control; + b[pos++]=sub.CurrentPosition.TrackNumber; + b[pos++]=sub.CurrentPosition.IndexNumber; + + if (msf) + { + int c; + for (c = 0; c < 4; c++) + b[pos++] = sub.CurrentPosition.AbsoluteAddress[c]; + for (c = 0; c < 4; c++) + b[pos++] = sub.CurrentPosition.TrackRelativeAddress[c]; + } + else + { + uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]); + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]); + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + } + + return 0x13; +} + +static void ioctl_eject(void) +{ + long size; + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL); + ioctl_close(); +} + +static void ioctl_load(void) +{ + long size; + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL); + ioctl_close(); + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); +} + +static void ioctl_readsector(uint8_t *b, int sector) +{ + LARGE_INTEGER pos; + long size; + if (!cdrom_drive) return; + + if (ioctl_cd_state == CD_PLAYING) + return; + + ioctl_cd_state = CD_STOPPED; + pos.QuadPart=sector*2048; + ioctl_open(0); + SetFilePointer(hIOCTL,pos.LowPart,&pos.HighPart,FILE_BEGIN); + ReadFile(hIOCTL,b,2048,&size,NULL); + ioctl_close(); +} + +static int is_track_audio(uint32_t pos) +{ + int c; + int control = 0; + + if (!tocvalid) + return 0; + + for (c = toc.FirstTrack; c < toc.LastTrack; c++) + { + uint32_t track_address = toc.TrackData[c].Address[3] + + (toc.TrackData[c].Address[2] * 75) + + (toc.TrackData[c].Address[1] * 75 * 60); + + if (track_address <= pos) + control = toc.TrackData[c].Control; + } + return (control & 4) ? 0 : 1; +} + +static int ioctl_is_track_audio(uint32_t pos, int ismsf) +{ + if (ismsf) + { + int m = (pos >> 16) & 0xff; + int s = (pos >> 8) & 0xff; + int f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + } + return is_track_audio(pos); +} + +static void ioctl_readsector_raw(uint8_t *b, int sector) +{ + LARGE_INTEGER pos; + long size; + uint32_t temp; + if (!cdrom_drive) return; + if (ioctl_cd_state == CD_PLAYING) + return; + + ioctl_cd_state = CD_STOPPED; + pos.QuadPart=sector*2048; /* Yes, 2048, the API specifies that. */ + ioctl_open(0); + /* This should read the actual raw sectors from the disc. */ + DeviceIoControl( hIOCTL, IOCTL_CDROM_RAW_READ, NULL, 0, b, 1, &size, NULL ); + ioctl_close(); +} + +static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + long size; + int c,d; + uint32_t temp; + if (!cdrom_drive) return 0; + ioctl_cd_state = CD_STOPPED; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL); + ioctl_close(); + tocvalid=1; +// pclog("Read TOC done! %i\n",single); + b[2]=toc.FirstTrack; + b[3]=toc.LastTrack; + d=0; + for (c=0;c<=toc.LastTrack;c++) + { + if (toc.TrackData[c].TrackNumber>=starttrack) + { + d=c; + break; + } + } + b[2]=toc.TrackData[c].TrackNumber; + last_block = 0; + for (c=d;c<=toc.LastTrack;c++) + { + uint32_t address; + if ((len+8)>maxlen) break; +// pclog("Len %i max %i Track %02X - %02X %02X %i %i %i %i %08X\n",len,maxlen,toc.TrackData[c].TrackNumber,toc.TrackData[c].Adr,toc.TrackData[c].Control,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3],MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3])); + b[len++]=0; /*Reserved*/ + b[len++]=(toc.TrackData[c].Adr<<4)|toc.TrackData[c].Control; + b[len++]=toc.TrackData[c].TrackNumber; + b[len++]=0; /*Reserved*/ + address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + if (address > last_block) + last_block = address; + + if (msf) + { + b[len++]=toc.TrackData[c].Address[0]; + b[len++]=toc.TrackData[c].Address[1]; + b[len++]=toc.TrackData[c].Address[2]; + b[len++]=toc.TrackData[c].Address[3]; + } + else + { + temp=MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + b[len++]=temp>>24; + b[len++]=temp>>16; + b[len++]=temp>>8; + b[len++]=temp; + } + if (single) break; + } + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); +/* pclog("Table of Contents (%i bytes) : \n",size); + pclog("First track - %02X\n",toc.FirstTrack); + pclog("Last track - %02X\n",toc.LastTrack); + for (c=0;c<=toc.LastTrack;c++) + pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + for (c=0;c<=toc.LastTrack;c++) + pclog("Track %02X - number %02X control %02X adr %02X address %06X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));*/ + return len; +} + +static int ioctl_readtoc_session(unsigned char *b, int msf, int maxlen) +{ + int len=4; + int size; + uint32_t temp; + CDROM_READ_TOC_EX toc_ex; + CDROM_TOC_SESSION_DATA toc; + if (!cdrom_drive) return 0; + ioctl_cd_state = CD_STOPPED; + memset(&toc_ex,0,sizeof(toc_ex)); + memset(&toc,0,sizeof(toc)); + toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION; + toc_ex.Msf=msf; + toc_ex.SessionTrack=0; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); + ioctl_close(); +// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber); + b[2]=toc.FirstCompleteSession; + b[3]=toc.LastCompleteSession; + b[len++]=0; /*Reserved*/ + b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control; + b[len++]=toc.TrackData[0].TrackNumber; + b[len++]=0; /*Reserved*/ + if (msf) + { + b[len++]=toc.TrackData[0].Address[0]; + b[len++]=toc.TrackData[0].Address[1]; + b[len++]=toc.TrackData[0].Address[2]; + b[len++]=toc.TrackData[0].Address[3]; + } + else + { + temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]); + b[len++]=temp>>24; + b[len++]=temp>>16; + b[len++]=temp>>8; + b[len++]=temp; + } + + return len; +} + +static int ioctl_readtoc_raw(unsigned char *b, int maxlen) +{ + int len=4; + int size; + uint32_t temp; + int i; + int BytesRead = 0; + CDROM_READ_TOC_EX toc_ex; + CDROM_TOC_FULL_TOC_DATA toc; + if (!cdrom_drive) return 0; + ioctl_cd_state = CD_STOPPED; + memset(&toc_ex,0,sizeof(toc_ex)); + memset(&toc,0,sizeof(toc)); + toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_FULL_TOC; + toc_ex.Msf=1; + toc_ex.SessionTrack=0; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); + ioctl_close(); +// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber); + b[2]=toc.FirstCompleteSession; + b[3]=toc.LastCompleteSession; + + size -= sizeof(CDROM_TOC_FULL_TOC_DATA); + size /= sizeof(toc.Descriptors[0]); + + for (i = 0; i <= size; i++) + { + b[len++]=toc.Descriptors[i].SessionNumber; + b[len++]=(toc.Descriptors[i].Adr<<4)|toc.Descriptors[i].Control; + b[len++]=0; + b[len++]=toc.Descriptors[i].Reserved1; /*Reserved*/ + b[len++]=toc.Descriptors[i].MsfExtra[0]; + b[len++]=toc.Descriptors[i].MsfExtra[1]; + b[len++]=toc.Descriptors[i].MsfExtra[2]; + b[len++]=toc.Descriptors[i].Zero; + b[len++]=toc.Descriptors[i].Msf[0]; + b[len++]=toc.Descriptors[i].Msf[1]; + b[len++]=toc.Descriptors[i].Msf[2]; + } + + return len; +} + +static uint32_t ioctl_size() +{ + return cdrom_capacity; +} + +static int ioctl_status() +{ + if (!(ioctl_ready) && (cdrom_drive <= 0)) + return CD_STATUS_EMPTY; + + switch(ioctl_cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + return CD_STATUS_STOPPED; + } +} + +void ioctl_reset() +{ + CDROM_TOC ltoc; + int temp; + long size; + + if (!cdrom_drive) + { + tocvalid = 0; + return; + } + + ioctl_open(0); + temp = DeviceIoControl(hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); + ioctl_close(); + + toc = ltoc; + tocvalid = 1; +} + +int ioctl_open(char d) +{ +// char s[8]; + if (!ioctl_inited) + { + sprintf(ioctl_path,"\\\\.\\%c:",d); + pclog("Path is %s\n",ioctl_path); + tocvalid=0; + } +// pclog("Opening %s\n",ioctl_path); + hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + if (!hIOCTL) + { + //fatal("IOCTL"); + } + atapi=&ioctl_atapi; + if (!ioctl_inited) + { + ioctl_inited=1; + CloseHandle(hIOCTL); + hIOCTL = NULL; + } + return 0; +} + +void ioctl_close(void) +{ + if (hIOCTL) + { + CloseHandle(hIOCTL); + hIOCTL = NULL; + } +} + +static void ioctl_exit(void) +{ + ioctl_stop(); + ioctl_inited=0; + tocvalid=0; +} + +static ATAPI ioctl_atapi= +{ + ioctl_ready, + ioctl_medium_changed, + ioctl_readtoc, + ioctl_readtoc_session, + ioctl_readtoc_raw, + ioctl_getcurrentsubchannel, + ioctl_readsector, + ioctl_readsector_raw, + ioctl_playaudio, + ioctl_seek, + ioctl_load, + ioctl_eject, + ioctl_pause, + ioctl_resume, + ioctl_size, + ioctl_status, + ioctl_is_track_audio, + ioctl_stop, + ioctl_exit +}; diff --git a/src/cdrom-ioctl.h b/src/cdrom-ioctl.h new file mode 100644 index 000000000..4d7ca2ff3 --- /dev/null +++ b/src/cdrom-ioctl.h @@ -0,0 +1,12 @@ +#ifndef CDROM_IOCTL_H +#define CDROM_IOCTL_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +extern int ioctl_open(char d); +extern void ioctl_reset(); + +extern void ioctl_close(void); + +#endif /* ! CDROM_IOCTL_H */ diff --git a/src/cdrom-iso.c b/src/cdrom-iso.c new file mode 100644 index 000000000..4a46f0507 --- /dev/null +++ b/src/cdrom-iso.c @@ -0,0 +1,396 @@ +/*ISO CD-ROM support*/ + +#include "ibm.h" +#include "ide.h" +#include "cdrom-iso.h" +#include + +static ATAPI iso_atapi; + +static uint32_t last_block = 0; +static uint64_t image_size = 0; +static int iso_inited = 0; +char iso_path[1024]; +void iso_close(void); +static FILE* iso_image; +static int iso_changed = 0; + +static uint32_t iso_cd_pos = 0, iso_cd_end = 0; + +void iso_audio_callback(int16_t *output, int len) +{ + memset(output, 0, len * 2); + return; +} + +void iso_audio_stop() +{ + pclog("iso_audio_stop stub\n"); +} + +static int get_track_nr(uint32_t pos) +{ + pclog("get_track_nr stub\n"); + return 0; +} + +static void iso_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ + pclog("iso_playaudio stub\n"); + return; +} + +static void iso_pause(void) +{ + pclog("iso_pause stub\n"); + return; +} + +static void iso_resume(void) +{ + pclog("iso_resume stub\n"); + return; +} + +static void iso_stop(void) +{ + pclog("iso_stop stub\n"); + return; +} + +static void iso_seek(uint32_t pos) +{ + pclog("iso_seek stub\n"); + return; +} + +static int iso_ready(void) +{ + if (strlen(iso_path) == 0) + { + return 0; + } + if (old_cdrom_drive != cdrom_drive) + { + // old_cdrom_drive = cdrom_drive; + return 1; + } + + if (iso_changed) + { + iso_changed = 0; + return 1; + } + + return 1; +} + +/* Always return 0, because there is no way to change the ISO without unmounting and remounting it. */ +static int iso_medium_changed(void) +{ + if (strlen(iso_path) == 0) + { + return 0; + } + if (old_cdrom_drive != cdrom_drive) + { + old_cdrom_drive = cdrom_drive; + return 0; + } + + if (iso_changed) + { + iso_changed = 0; + return 0; + } + + return 0; +} + +static uint8_t iso_getcurrentsubchannel(uint8_t *b, int msf) +{ + pclog("iso_getcurrentsubchannel stub\n"); + return 0; +} + +static void iso_eject(void) +{ + pclog("iso_eject stub\n"); +} + +static void iso_load(void) +{ + pclog("iso_load stub\n"); +} + +static void iso_readsector(uint8_t *b, int sector) +{ + if (!cdrom_drive) return; + iso_image = fopen(iso_path, "rb"); + fseek(iso_image,sector*2048,SEEK_SET); + fread(b,2048,1,iso_image); + fclose(iso_image); +} + +static void lba_to_msf(uint8_t *buf, int lba) +{ + double dlba = (double) lba + 150; + buf[2] = (uint8_t) (((uint32_t) dlba) % 75); + dlba /= 75; + buf[1] = (uint8_t) (((uint32_t) dlba) % 60); + dlba /= 60; + buf[0] = (uint8_t) dlba; +} + +#if 0 +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; +} +#endif + +static void iso_readsector_raw(uint8_t *b, int sector) +{ + uint32_t temp; + if (!cdrom_drive) return; + iso_image = fopen(iso_path, "rb"); + fseek(iso_image, sector*2048, SEEK_SET); + fread(b+16, 2048, 1, iso_image); + fclose(iso_image); + + /* sync bytes */ + b[0] = 0; + memset(b + 1, 0xff, 10); + b[11] = 0; + b += 12; + lba_to_msf(b, sector); + b[3] = 1; /* mode 1 data */ + b += 4; + b += 2048; + memset(b, 0, 288); +} + +static int iso_readtoc(unsigned char *buf, unsigned char start_track, int msf, int maxlen, int single) +{ + uint8_t *q; + int len; + + if (start_track > 1 && start_track != 0xaa) + return -1; + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + if (start_track <= 1) { + *q++ = 0; /* reserved */ + *q++ = 0x14; /* ADR, control */ + *q++ = 1; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, 0); + q += 3; + } else { + /* sector 0 */ + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + } + } + /* lead out track */ + *q++ = 0; /* reserved */ + *q++ = 0x16; /* ADR, control */ + *q++ = 0xaa; /* track number */ + *q++ = 0; /* reserved */ + last_block = image_size >> 11; + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, last_block); + q += 3; + } else { + *q++ = last_block >> 24; + *q++ = last_block >> 16; + *q++ = last_block >> 8; + *q++ = last_block; + } + len = q - buf; + buf[0] = (uint8_t)(((len-2) >> 8) & 0xff); + buf[1] = (uint8_t)((len-2) & 0xff); + return len; +} + +static int iso_readtoc_session(unsigned char *buf, int msf, int maxlen) +{ + uint8_t *q; + + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa0; /* lead-in */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + + return 12; +} + +static int iso_readtoc_raw(unsigned char *buf, int maxlen) +{ + uint8_t *q; + int len; + + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa0; /* lead-in */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* first track */ + *q++ = 0x00; /* disk type */ + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa1; + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* last track */ + *q++ = 0x00; + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa2; /* lead-out */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + last_block = image_size >> 11; + /* this is raw, must be msf */ + *q++ = 0; /* reserved */ + lba_to_msf(q, last_block); + q += 3; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* ADR, control */ + *q++ = 0; /* track number */ + *q++ = 1; /* point */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + /* same here */ + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + + len = q - buf; + buf[0] = (uint8_t)(((len-2) >> 8) & 0xff); + buf[1] = (uint8_t)((len-2) & 0xff); + return len; +} + +static uint32_t iso_size() +{ + unsigned char b[4096]; + + atapi->readtoc(b, 0, 0, 4096, 0); + + return last_block; +} + +static int iso_status() +{ + if (!(iso_ready()) && (cdrom_drive != 200)) return CD_STATUS_EMPTY; + + return CD_STATUS_DATA_ONLY; +} + +void iso_reset() +{ +} + +int iso_open(char *fn) +{ + if (strcmp(fn, iso_path) != 0) + { + iso_changed = 1; + } + /* Make sure iso_changed stays when changing from ISO to another ISO. */ + if (!iso_inited && (cdrom_drive != 200)) iso_changed = 0; + if (!iso_inited || iso_changed) + { + sprintf(iso_path, "%s", fn); + pclog("Path is %s\n", iso_path); + } + iso_image = fopen(iso_path, "rb"); + atapi = &iso_atapi; + if (!iso_inited || iso_changed) + { + if (!iso_inited) iso_inited = 1; + fclose(iso_image); + } + + struct stat st; + stat(iso_path, &st); + image_size = st.st_size; + + return 0; +} + +void iso_close(void) +{ + if (iso_image) fclose(iso_image); + memset(iso_path, 0, 1024); +} + +static void iso_exit(void) +{ + // iso_stop(); + iso_inited = 0; +} + +static int iso_is_track_audio(uint32_t pos, int ismsf) +{ + return 0; +} + +static ATAPI iso_atapi = +{ + iso_ready, + iso_medium_changed, + iso_readtoc, + iso_readtoc_session, + iso_readtoc_raw, + iso_getcurrentsubchannel, + iso_readsector, + iso_readsector_raw, + iso_playaudio, + iso_seek, + iso_load, + iso_eject, + iso_pause, + iso_resume, + iso_size, + iso_status, + iso_is_track_audio, + iso_stop, + iso_exit +}; diff --git a/src/cdrom-iso.h b/src/cdrom-iso.h new file mode 100644 index 000000000..3ff743486 --- /dev/null +++ b/src/cdrom-iso.h @@ -0,0 +1,14 @@ +#ifndef CDROM_ISO_H +#define CDROM_ISO_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +extern char iso_path[1024]; + +extern int iso_open(char *fn); +extern void iso_reset(); + +extern void iso_close(void); + +#endif /* ! CDROM_ISO_H */ diff --git a/src/cdrom-null.c b/src/cdrom-null.c new file mode 100644 index 000000000..dc2c02a2c --- /dev/null +++ b/src/cdrom-null.c @@ -0,0 +1,139 @@ +#include "ibm.h" +#include "ide.h" +#include "cdrom-ioctl.h" + +int cdrom_drive; + +static ATAPI null_atapi; + +void cdrom_null_audio_callback(int16_t *output, int len) +{ + memset(output, 0, len * 2); +} + +void cdrom_null_audio_stop() +{ +} + +static void null_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ +} + +static void null_pause(void) +{ +} + +static void null_resume(void) +{ +} + +static void null_stop(void) +{ +} + +static void null_seek(uint32_t pos) +{ +} + +static int null_ready(void) +{ + return 0; +} + +/* Always return 0, the contents of a null CD-ROM drive never change. */ +static int null_medium_changed(void) +{ + return 0; +} + +static uint8_t null_getcurrentsubchannel(uint8_t *b, int msf) +{ + return 0x13; +} + +static void null_eject(void) +{ +} + +static void null_load(void) +{ +} + +static void null_readsector(uint8_t *b, int sector) +{ +} + +static void null_readsector_raw(uint8_t *b, int sector) +{ +} + +static int null_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + return 0; +} + +static int null_readtoc_session(unsigned char *b, int msf, int maxlen) +{ + return 0; +} + +static int null_readtoc_raw(unsigned char *b, int maxlen) +{ + return 0; +} + +static uint32_t null_size() +{ + return 0; +} + +static int null_status() +{ + return CD_STATUS_EMPTY; +} + +void cdrom_null_reset() +{ +} + +int cdrom_null_open(char d) +{ + atapi = &null_atapi; + return 0; +} + +void null_close(void) +{ +} + +static void null_exit(void) +{ +} + +static int null_is_track_audio(uint32_t pos, int ismsf) +{ + return 0; +} + +static ATAPI null_atapi = +{ + null_ready, + null_medium_changed, + null_readtoc, + null_readtoc_session, + null_readtoc_raw, + null_getcurrentsubchannel, + null_readsector, + null_readsector_raw, + null_playaudio, + null_seek, + null_load, + null_eject, + null_pause, + null_resume, + null_size, + null_status, + null_is_track_audio, + null_stop, + null_exit +}; diff --git a/src/cdrom-null.h b/src/cdrom-null.h new file mode 100644 index 000000000..007e86478 --- /dev/null +++ b/src/cdrom-null.h @@ -0,0 +1,11 @@ +#ifndef CDROM_IOCTL_H +#define CDROM_IOCTL_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +extern int cdrom_null_open(char d); +extern void cdrom_null_reset(); +extern void null_close(); + +#endif /* ! CDROM_IOCTL_H */ diff --git a/src/codegen.c b/src/codegen.c new file mode 100644 index 000000000..5667c9bad --- /dev/null +++ b/src/codegen.c @@ -0,0 +1,21 @@ +#include "ibm.h" +#include "x86_ops.h" +#include "mem.h" +#include "codegen.h" + +void (*codegen_timing_start)(); +void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); +void (*codegen_timing_block_start)(); +void (*codegen_timing_block_end)(); + +void codegen_timing_set(codegen_timing_t *timing) +{ + codegen_timing_start = timing->start; + codegen_timing_prefix = timing->prefix; + codegen_timing_opcode = timing->opcode; + codegen_timing_block_start = timing->block_start; + codegen_timing_block_end = timing->block_end; +} + +int codegen_in_recompile; diff --git a/src/codegen.h b/src/codegen.h new file mode 100644 index 000000000..b9a53c887 --- /dev/null +++ b/src/codegen.h @@ -0,0 +1,340 @@ +#include "mem.h" + +#ifdef __amd64__ +#include "codegen_x86-64.h" +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 +#include "codegen_x86.h" +#else +#error Dynamic recompiler not implemented on your platform +#endif + +/*Handling self-modifying code (of which there is a lot on x86) : + + PCem tracks a 'dirty mask' for each physical page, in which each bit + represents 64 bytes. This is only tracked for pages that have code in - when a + page first has a codeblock generated, it is evicted from the writelookup and + added to the page_lookup for this purpose. When in the page_lookup, each write + will go through the mem_write_ram*_page() functions and set the dirty mask + appropriately. + + Each codeblock also contains a code mask (actually two masks, one for each + page the block is/may be in), again with each bit representing 64 bytes. + + Each page has a list of codeblocks present in it. As each codeblock can span + up to two pages, two lists are present. + + When a codeblock is about to be executed, the code masks are compared with the + dirty masks for the relevant pages. If either intersect, then + codegen_check_flush() is called on the affected page(s), and all affected + blocks are evicted. + + The 64 byte granularity appears to work reasonably well for most cases, + avoiding most unnecessary evictions (eg when code & data are stored in the + same page). +*/ + +typedef struct codeblock_t +{ + /*Previous and next pointers, for the codeblock list associated with + each physical page. Two sets of pointers, as a codeblock can be + present in two pages.*/ + struct codeblock_t *prev, *next; + struct codeblock_t *prev_2, *next_2; + + /*Pointers for codeblock tree, used to search for blocks when hash lookup + fails.*/ + struct codeblock_t *parent, *left, *right; + + uint32_t pc; + uint32_t _cs; + uint32_t endpc; + uint32_t phys, phys_2; + uint32_t use32; + int stack32; + int pnt; + int ins; + uint64_t page_mask, page_mask2; + + uint8_t data[2048]; +} codeblock_t; + +static inline codeblock_t *codeblock_tree_find(uint32_t phys) +{ + codeblock_t *block = pages[phys >> 12].head; + + while (block) + { + if (phys == block->phys) + break; + else if (phys < block->phys) + block = block->left; + else + block = block->right; + } + + return block; +} + +static inline void codeblock_tree_add(codeblock_t *new_block) +{ + codeblock_t *block = pages[new_block->phys >> 12].head; + + if (!block) + { + pages[new_block->phys >> 12].head = new_block; + new_block->parent = new_block->left = new_block->right = NULL; + } + else + { + codeblock_t *old_block = NULL; + while (block) + { + old_block = block; + + if (new_block->phys < old_block->phys) + block = block->left; + else + block = block->right; + } + + if (new_block->phys < old_block->phys) + old_block->left = new_block; + else + old_block->right = new_block; + + new_block->parent = old_block; + new_block->left = new_block->right = NULL; + } +} + +static inline void codeblock_tree_delete(codeblock_t *block) +{ + codeblock_t *parent = block->parent; + + if (!block->left && !block->right) + { + /*Easy case - remove from parent*/ + if (!parent) + pages[block->phys >> 12].head = NULL; + else + { + if (parent->left == block) + parent->left = NULL; + if (parent->right == block) + parent->right = NULL; + } + return; + } + else if (!block->left) + { + /*Only right node*/ + if (!parent) + { + pages[block->phys >> 12].head = block->right; + pages[block->phys >> 12].head->parent = NULL; + } + else + { + if (parent->left == block) + { + parent->left = block->right; + parent->left->parent = parent; + } + if (parent->right == block) + { + parent->right = block->right; + parent->right->parent = parent; + } + } + return; + } + else if (!block->right) + { + /*Only left node*/ + if (!parent) + { + pages[block->phys >> 12].head = block->left; + pages[block->phys >> 12].head->parent = NULL; + } + else + { + if (parent->left == block) + { + parent->left = block->left; + parent->left->parent = parent; + } + if (parent->right == block) + { + parent->right = block->left; + parent->right->parent = parent; + } + } + return; + } + else + { + /*Difficult case - node has two children. Walk right child to find lowest node*/ + codeblock_t *lowest = block->right, *highest; + codeblock_t *old_parent; + + while (lowest->left) + lowest = lowest->left; + + old_parent = lowest->parent; + + /*Replace deleted node with lowest node*/ + if (!parent) + pages[block->phys >> 12].head = lowest; + else + { + if (parent->left == block) + parent->left = lowest; + if (parent->right == block) + parent->right = lowest; + } + + lowest->parent = parent; + lowest->left = block->left; + if (lowest->left) + lowest->left->parent = lowest; + + old_parent->left = NULL; + + highest = lowest->right; + if (!highest) + { + if (lowest != block->right) + { + lowest->right = block->right; + block->right->parent = lowest; + } + return; + } + + while (highest->right) + highest = highest->right; + + if (block->right && block->right != lowest) + { + highest->right = block->right; + block->right->parent = highest; + } + } +} + +#define PAGE_MASK_MASK 63 +#define PAGE_MASK_SHIFT 6 + +extern codeblock_t *codeblock; + +extern codeblock_t **codeblock_hash; + +void codegen_init(); +void codegen_reset(); +void codegen_block_init(uint32_t phys_addr); +void codegen_block_remove(); +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc); +void codegen_generate_seg_restore(); +void codegen_check_abrt(); +void codegen_set_op32(); +void codegen_flush(); +void codegen_check_flush(struct page_t *page, uint64_t mask, uint32_t phys_addr); + +extern int cpu_block_end; + +extern int cpu_recomp_blocks, cpu_recomp_ins, cpu_recomp_full_ins, cpu_new_blocks; +extern int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; +extern int cpu_recomp_flushes, cpu_recomp_flushes_latched; +extern int cpu_recomp_evicted, cpu_recomp_evicted_latched; +extern int cpu_recomp_reuse, cpu_recomp_reuse_latched; +extern int cpu_recomp_removed, cpu_recomp_removed_latched; + +extern int cpu_reps, cpu_reps_latched; +extern int cpu_notreps, cpu_notreps_latched; + +extern int codegen_block_cycles; + +extern void (*codegen_timing_start)(); +extern void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); +extern void (*codegen_timing_block_start)(); +extern void (*codegen_timing_block_end)(); + +typedef struct codegen_timing_t +{ + void (*start)(); + void (*prefix)(uint8_t prefix, uint32_t fetchdat); + void (*opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); + void (*block_start)(); + void (*block_end)(); +} codegen_timing_t; + +extern codegen_timing_t codegen_timing_pentium; +extern codegen_timing_t codegen_timing_686; +extern codegen_timing_t codegen_timing_486; +extern codegen_timing_t codegen_timing_winchip; + +void codegen_timing_set(codegen_timing_t *timing); + +extern int block_current; +extern int block_pos; + +#define CPU_BLOCK_END() cpu_block_end = 1 + +static inline void addbyte(uint8_t val) +{ + codeblock[block_current].data[block_pos++] = val; + if (block_pos >= 1760) + { + CPU_BLOCK_END(); + } +} + +static inline void addword(uint16_t val) +{ + *(uint16_t *)&codeblock[block_current].data[block_pos] = val; + block_pos += 2; + if (block_pos >= 1720) + { + CPU_BLOCK_END(); + } +} + +static inline void addlong(uint32_t val) +{ + *(uint32_t *)&codeblock[block_current].data[block_pos] = val; + block_pos += 4; + if (block_pos >= 1720) + { + CPU_BLOCK_END(); + } +} + +static inline void addquad(uint64_t val) +{ + *(uint64_t *)&codeblock[block_current].data[block_pos] = val; + block_pos += 8; + if (block_pos >= 1720) + { + CPU_BLOCK_END(); + } +} + +/*Current physical page of block being recompiled. -1 if no recompilation taking place */ +extern uint32_t recomp_page; + +extern x86seg *op_ea_seg; +extern int op_ssegs; +extern uint32_t op_old_pc; + +/*Set to 1 if flags have been changed in the block being recompiled, and hence + flags_op is known and can be relied on */ +extern int codegen_flags_changed; + +extern int codegen_fpu_entered; +extern int codegen_mmx_entered; + +extern int codegen_fpu_loaded_iq[8]; +extern int codegen_reg_loaded[8]; + +extern int codegen_in_recompile; diff --git a/src/codegen_ops.c b/src/codegen_ops.c new file mode 100644 index 000000000..083c80b7d --- /dev/null +++ b/src/codegen_ops.c @@ -0,0 +1,497 @@ +#include "ibm.h" +#include "x86.h" +#include "x86_ops.h" +#include "x86_flags.h" +#include "x87.h" +#include "386_common.h" +#include "cpu.h" +#include "codegen.h" +#include "codegen_ops.h" + +#ifdef __amd64__ +#include "codegen_ops_x86-64.h" +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 +#include "codegen_ops_x86.h" +#endif + +#include "codegen_ops_arith.h" +#include "codegen_ops_fpu.h" +#include "codegen_ops_jump.h" +#include "codegen_ops_logic.h" +#include "codegen_ops_misc.h" +#include "codegen_ops_mmx.h" +#include "codegen_ops_mov.h" +#include "codegen_ops_shift.h" +#include "codegen_ops_stack.h" +#include "codegen_ops_xchg.h" + +RecompOpFn recomp_opcodes[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropADD_b_rmw, ropADD_w_rmw, ropADD_b_rm, ropADD_w_rm, ropADD_AL_imm, ropADD_AX_imm, ropPUSH_ES_16, NULL, ropOR_b_rmw, ropOR_w_rmw, ropOR_b_rm, ropOR_w_rm, ropOR_AL_imm, ropOR_AX_imm, ropPUSH_CS_16, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_SS_16, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_DS_16, NULL, +/*20*/ ropAND_b_rmw, ropAND_w_rmw, ropAND_b_rm, ropAND_w_rm, ropAND_AL_imm, ropAND_AX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_w_rmw, ropSUB_b_rm, ropSUB_w_rm, ropSUB_AL_imm, ropSUB_AX_imm, NULL, NULL, +/*30*/ ropXOR_b_rmw, ropXOR_w_rmw, ropXOR_b_rm, ropXOR_w_rm, ropXOR_AL_imm, ropXOR_AX_imm, NULL, NULL, ropCMP_b_rmw, ropCMP_w_rmw, ropCMP_b_rm, ropCMP_w_rm, ropCMP_AL_imm, ropCMP_AX_imm, NULL, NULL, + +/*40*/ ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, +/*50*/ ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_16, NULL, ropPUSH_imm_b16,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO, ropJNO, ropJB, ropJNB, ropJE, ropJNE, ropJBE, ropJNBE, ropJS, ropJNS, ropJP, ropJNP, ropJL, ropJNL, ropJLE, ropJNLE, + +/*80*/ rop80, rop81_w, rop80, rop83_w, ropTEST_b_rm, ropTEST_w_rm, ropXCHG_b, ropXCHG_w, ropMOV_b_r, ropMOV_w_r, ropMOV_r_b, ropMOV_r_w, NULL, ropLEA_w, NULL, NULL, +/*90*/ ropNOP, ropXCHG_AX_CX, ropXCHG_AX_DX, ropXCHG_AX_BX, ropXCHG_AX_SP, ropXCHG_AX_BP, ropXCHG_AX_SI, ropXCHG_AX_DI, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_a, ropMOV_AX_a, ropMOV_a_AL, ropMOV_a_AX, NULL, NULL, NULL, NULL, ropTEST_AL_imm, ropTEST_AX_imm, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, + +/*c0*/ ropC0, ropC1_w, ropRET_imm_16, ropRET_16, NULL, NULL, ropMOV_b_imm, ropMOV_w_imm, NULL, ropLEAVE_16, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_w, NULL, NULL, NULL, NULL, ropCLD, ropSTD, NULL, ropFF_16, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropADD_b_rmw, ropADD_l_rmw, ropADD_b_rm, ropADD_l_rm, ropADD_AL_imm, ropADD_EAX_imm, ropPUSH_ES_32, NULL, ropOR_b_rmw, ropOR_l_rmw, ropOR_b_rm, ropOR_l_rm, ropOR_AL_imm, ropOR_EAX_imm, ropPUSH_CS_32, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_SS_32, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_DS_32, NULL, +/*20*/ ropAND_b_rmw, ropAND_l_rmw, ropAND_b_rm, ropAND_l_rm, ropAND_AL_imm, ropAND_EAX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_l_rmw, ropSUB_b_rm, ropSUB_l_rm, ropSUB_AL_imm, ropSUB_EAX_imm, NULL, NULL, +/*30*/ ropXOR_b_rmw, ropXOR_l_rmw, ropXOR_b_rm, ropXOR_l_rm, ropXOR_AL_imm, ropXOR_EAX_imm, NULL, NULL, ropCMP_b_rmw, ropCMP_l_rmw, ropCMP_b_rm, ropCMP_l_rm, ropCMP_AL_imm, ropCMP_EAX_imm, NULL, NULL, + +/*40*/ ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, +/*50*/ ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_32, NULL, ropPUSH_imm_b32,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO, ropJNO, ropJB, ropJNB, ropJE, ropJNE, ropJBE, ropJNBE, ropJS, ropJNS, ropJP, ropJNP, ropJL, ropJNL, ropJLE, ropJNLE, + +/*80*/ rop80, rop81_l, rop80, rop83_l, ropTEST_b_rm, ropTEST_l_rm, ropXCHG_b, ropXCHG_l, ropMOV_b_r, ropMOV_l_r, ropMOV_r_b, ropMOV_r_l, NULL, ropLEA_l, NULL, NULL, +/*90*/ ropNOP, ropXCHG_EAX_ECX,ropXCHG_EAX_EDX,ropXCHG_EAX_EBX,ropXCHG_EAX_ESP,ropXCHG_EAX_EBP,ropXCHG_EAX_ESI,ropXCHG_EAX_EDI,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_a, ropMOV_EAX_a, ropMOV_a_AL, ropMOV_a_EAX, NULL, NULL, NULL, NULL, ropTEST_AL_imm, ropTEST_EAX_imm,NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, + +/*c0*/ ropC0, ropC1_l, ropRET_imm_32, ropRET_32, NULL, NULL, ropMOV_b_imm, ropMOV_l_imm, NULL, ropLEAVE_32, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_l, NULL, NULL, NULL, NULL, ropCLD, ropSTD, NULL, ropFF_32 +}; + +RecompOpFn recomp_opcodes_0f[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropEMMS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropJO_w, ropJNO_w, ropJB_w, ropJNB_w, ropJE_w, ropJNE_w, ropJBE_w, ropJNBE_w, ropJS_w, ropJNS_w, ropJP_w, ropJNP_w, ropJL_w, ropJNL_w, ropJLE_w, ropJNLE_w, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropMOVZX_w_b, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_w_b, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ ropPUNPCKLBW, ropPUNPCKLWD, ropPUNPCKLDQ, ropPACKSSWB, ropPCMPGTB, ropPCMPGTW, ropPCMPGTD, ropPACKUSWB, ropPUNPCKHBW, ropPUNPCKHWD, ropPUNPCKHDQ, ropPACKSSDW, NULL, NULL, ropMOVD_mm_l, ropMOVQ_mm_q, +/*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, ropEMMS, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_l_mm, ropMOVQ_q_mm, + +/*80*/ ropJO_l, ropJNO_l, ropJB_l, ropJNB_l, ropJE_l, ropJNE_l, ropJBE_l, ropJNBE_l, ropJS_l, ropJNS_l, ropJP_l, ropJNP_l, ropJL_l, ropJNL_l, ropJLE_l, ropJNLE_l, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropMOVZX_l_b, ropMOVZX_l_w, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_l_b, ropMOVSX_l_w, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, ropPSRLW, ropPSRLD, ropPSRLQ, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN, +/*e0*/ NULL, ropPSRAW, ropPSRAD, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR, +/*f0*/ NULL, ropPSLLW, ropPSLLD, ropPSLLQ, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, NULL, +}; + + +RecompOpFn recomp_opcodes_d8[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, +}; + +RecompOpFn recomp_opcodes_d9[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*80*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*80*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_da[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*10*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*20*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*30*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*40*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*50*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*60*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*70*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*80*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*90*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*a0*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*b0*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*10*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*20*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*30*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*40*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*50*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*60*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*70*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*80*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*90*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*a0*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*b0*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_db[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_dc[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, +}; + +RecompOpFn recomp_opcodes_dd[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_de[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*10*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*20*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*30*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*40*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*50*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*60*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*70*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*80*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*90*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*a0*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*b0*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*c0*/ ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*10*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*20*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*30*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*40*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*50*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*60*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*70*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*80*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*90*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*a0*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*b0*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*c0*/ ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, +}; + +RecompOpFn recomp_opcodes_df[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; diff --git a/src/codegen_ops.h b/src/codegen_ops.h new file mode 100644 index 000000000..36b21918e --- /dev/null +++ b/src/codegen_ops.h @@ -0,0 +1,37 @@ +typedef uint32_t (*RecompOpFn)(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block); + +extern RecompOpFn recomp_opcodes[512]; +extern RecompOpFn recomp_opcodes_0f[512]; +extern RecompOpFn recomp_opcodes_d8[512]; +extern RecompOpFn recomp_opcodes_d9[512]; +extern RecompOpFn recomp_opcodes_da[512]; +extern RecompOpFn recomp_opcodes_db[512]; +extern RecompOpFn recomp_opcodes_dc[512]; +extern RecompOpFn recomp_opcodes_dd[512]; +extern RecompOpFn recomp_opcodes_de[512]; +extern RecompOpFn recomp_opcodes_df[512]; + +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 +#define REG_AX 0 +#define REG_CX 1 +#define REG_DX 2 +#define REG_BX 3 +#define REG_SP 4 +#define REG_BP 5 +#define REG_SI 6 +#define REG_DI 7 +#define REG_AL 0 +#define REG_AH 4 +#define REG_CL 1 +#define REG_CH 5 +#define REG_DL 2 +#define REG_DH 6 +#define REG_BL 3 +#define REG_BH 7 diff --git a/src/codegen_ops_arith.h b/src/codegen_ops_arith.h new file mode 100644 index 000000000..1753bde8f --- /dev/null +++ b/src/codegen_ops_arith.h @@ -0,0 +1,816 @@ +static uint32_t ropINC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC(flags_rebuild_c); + + host_reg = LOAD_REG_W(opcode & 7); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} +static uint32_t ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC(flags_rebuild_c); + + host_reg = LOAD_REG_L(opcode & 7); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} +static uint32_t ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC(flags_rebuild_c); + + host_reg = LOAD_REG_W(opcode & 7); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} +static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC(flags_rebuild_c); + + host_reg = LOAD_REG_L(opcode & 7); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} + +#define ROP_ARITH_RMW(name, op, writeback) \ + static uint32_t rop ## name ## _b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_B(fetchdat & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_W(fetchdat & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_L(fetchdat & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } + +#define ROP_ARITH_RM(name, op, writeback) \ + static uint32_t rop ## name ## _b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_B(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_B(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_W(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_W(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_L(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_L(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } + +ROP_ARITH_RMW(ADD, ADD, 1) +ROP_ARITH_RMW(SUB, SUB, 1) +ROP_ARITH_RM(ADD, ADD, 1) +ROP_ARITH_RM(SUB, SUB, 1) + +static uint32_t ropCMP_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_B(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +static uint32_t ropCMP_b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + dst_reg = LOAD_REG_B(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + dst_reg = 0; + } + + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + dst_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + dst_reg = 0; + } \ + + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + dst_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + dst_reg = 0; + } + + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} + + +static uint32_t ropADD_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + fetchdat = fastreadl(cs + op_pc); + ADD_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 4; +} + +static uint32_t ropCMP_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + fetchdat = fastreadl(cs + op_pc); + host_reg = CMP_HOST_REG_IMM_L(host_reg, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 4; +} + +static uint32_t ropSUB_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + fetchdat = fastreadl(cs + op_pc); + SUB_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 4; +} + +static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + host_reg = LOAD_REG_B(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_B(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD8); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN8); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm | 0xffffff00); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN8); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_B(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN8); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_B(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + break; + } + + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_B_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} + +static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xffff; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD16); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + } + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_W_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 3; +} +static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + imm = fastreadl(cs + op_pc + 1); + + host_reg = LOAD_REG_L(fetchdat & 7); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD32); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + } + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_L_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 5; +} + +static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + if (imm & 0x80) + imm |= 0xff80; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD16); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + } + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_W_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + host_reg = LOAD_REG_L(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + if (imm & 0x80) + imm |= 0xffffff80; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD32); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + } + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_L_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} diff --git a/src/codegen_ops_fpu.h b/src/codegen_ops_fpu.h new file mode 100644 index 000000000..d300926da --- /dev/null +++ b/src/codegen_ops_fpu.h @@ -0,0 +1,601 @@ +static uint32_t ropFXCH(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FXCH(opcode & 7); + + return op_pc; +} + +static uint32_t ropFLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FLD(opcode & 7); + + return op_pc; +} + +static uint32_t ropFST(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FST(opcode & 7); + + return op_pc; +} +static uint32_t ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FST(opcode & 7); + FP_POP(); + + return op_pc; +} + + +static uint32_t ropFLDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_LOAD_S(); + + return op_pc + 1; +} +static uint32_t ropFLDd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_Q(target_seg); + + FP_LOAD_D(); + + return op_pc + 1; +} + +static uint32_t ropFILDw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_W(target_seg); + + FP_LOAD_IW(); + + return op_pc + 1; +} +static uint32_t ropFILDl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_LOAD_IL(); + + return op_pc + 1; +} +static uint32_t ropFILDq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_Q(target_seg); + + FP_LOAD_IQ(); + + codegen_fpu_loaded_iq[(TOP - 1) & 7] = 1; + + return op_pc + 1; +} + +static uint32_t ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + host_reg = FP_LOAD_REG(0); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + + return op_pc + 1; +} +static uint32_t ropFSTd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg1, host_reg2; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + FP_LOAD_REG_D(0, &host_reg1, &host_reg2); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 7); + + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); + + return op_pc + 1; +} + +static uint32_t ropFSTPs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFSTs(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} +static uint32_t ropFSTPd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFSTd(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} + +#define ropFarith(name, size, load, op) \ +static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + x86seg *target_seg; \ + \ + FP_ENTER(); \ + op_pc--; \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + load(target_seg); \ + \ + op(FPU_ ## name); \ + \ + return op_pc + 1; \ +} + +ropFarith(ADD, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(DIV, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(DIVR, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(MUL, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(SUB, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(SUBR, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(ADD, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(DIV, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(DIVR, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(MUL, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(SUB, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(SUBR, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(ADD, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(DIV, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(DIVR, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(MUL, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(SUB, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(SUBR, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(ADD, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(DIV, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(DIVR, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(MUL, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(SUB, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(SUBR, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); + +#define ropFcompare(name, size, load, op) \ +static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + x86seg *target_seg; \ + \ + FP_ENTER(); \ + op_pc--; \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + load(target_seg); \ + \ + op(); \ + \ + return op_pc + 1; \ +} \ +static uint32_t ropF ## name ## P ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + uint32_t new_pc = ropF ## name ## size(opcode, fetchdat, op_32, op_pc, block); \ + \ + FP_POP(); \ + \ + return new_pc; \ +} + +ropFcompare(COM, s, MEM_LOAD_ADDR_EA_L, FP_COMPARE_S); +ropFcompare(COM, d, MEM_LOAD_ADDR_EA_Q, FP_COMPARE_D); +ropFcompare(COM, iw, MEM_LOAD_ADDR_EA_W, FP_COMPARE_IW); +ropFcompare(COM, il, MEM_LOAD_ADDR_EA_L, FP_COMPARE_IL); + +/*static uint32_t ropFADDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_ADD); + + return op_pc + 1; +} +static uint32_t ropFDIVs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_DIV); + + return op_pc + 1; +} +static uint32_t ropFMULs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_MUL); + + return op_pc + 1; +} +static uint32_t ropFSUBs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_SUB); + + return op_pc + 1; +}*/ + + +static uint32_t ropFADD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_ADD, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFCOM(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_COMPARE_REG(0, opcode & 7); + + return op_pc; +} +static uint32_t ropFDIV(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIV, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFDIVR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIVR, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFMUL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_MUL, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFSUB(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUB, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFSUBR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUBR, 0, opcode & 7); + + return op_pc; +} + +static uint32_t ropFADDr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_ADD, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFDIVr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIV, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFDIVRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIVR, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFMULr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_MUL, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFSUBr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUB, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFSUBRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUBR, opcode & 7, 0); + + return op_pc; +} + +static uint32_t ropFADDP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_ADD, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFCOMP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_COMPARE_REG(0, opcode & 7); + FP_POP(); + + return op_pc; +} +static uint32_t ropFDIVP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIV, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFDIVRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIVR, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFMULP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_MUL, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFSUBP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUB, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFSUBRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUBR, opcode & 7, 0); + FP_POP(); + + return op_pc; +} + + +static uint32_t ropFSTSW_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + FP_ENTER(); + host_reg = LOAD_VAR_W(&npxs); + STORE_REG_TARGET_W_RELEASE(host_reg, REG_AX); + + return op_pc; +} + + +static uint32_t ropFISTw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + host_reg = FP_LOAD_REG_INT_W(0); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + + return op_pc + 1; +} +static uint32_t ropFISTl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + host_reg = FP_LOAD_REG_INT(0); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + + return op_pc + 1; +} + +static uint32_t ropFISTPw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFISTw(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} +static uint32_t ropFISTPl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFISTl(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} +static uint32_t ropFISTPq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg1, host_reg2; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + FP_LOAD_REG_INT_Q(0, &host_reg1, &host_reg2); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); + + FP_POP(); + + return op_pc + 1; +} + + +static uint32_t ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + STORE_HOST_REG_ADDR_W((uintptr_t)&npxc, 0); + + return op_pc + 1; +} +static uint32_t ropFSTCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + CHECK_SEG_WRITE(target_seg); + + host_reg = LOAD_VAR_W((uintptr_t)&npxc); + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + + return op_pc + 1; +} diff --git a/src/codegen_ops_jump.h b/src/codegen_ops_jump.h new file mode 100644 index 000000000..8dba96c7c --- /dev/null +++ b/src/codegen_ops_jump.h @@ -0,0 +1,270 @@ +static uint32_t ropJMP_r8(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fetchdat & 0xff; + + if (offset & 0x80) + offset |= 0xffffff00; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+1+offset); + + return -1; +} + +static uint32_t ropJMP_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); + + return -1; +} + +static uint32_t ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fastreadl(cs + op_pc); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); + + return -1; +} + + +static uint32_t ropJCXZ(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fetchdat & 0xff; + + if (offset & 0x80) + offset |= 0xffffff00; + + if (op_32 & 0x200) + { + int host_reg = LOAD_REG_L(REG_ECX); + TEST_ZERO_JUMP_L(host_reg, op_pc+1+offset, 0); + } + else + { + int host_reg = LOAD_REG_W(REG_CX); + TEST_ZERO_JUMP_W(host_reg, op_pc+1+offset, 0); + } + + return op_pc+1; +} + +static uint32_t ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fetchdat & 0xff; + + if (offset & 0x80) + offset |= 0xffffff00; + + if (op_32 & 0x200) + { + int host_reg = LOAD_REG_L(REG_ECX); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_REG_L_RELEASE(host_reg); + TEST_NONZERO_JUMP_L(host_reg, op_pc+1+offset, 0); + } + else + { + int host_reg = LOAD_REG_W(REG_CX); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_REG_W_RELEASE(host_reg); + TEST_NONZERO_JUMP_W(host_reg, op_pc+1+offset, 0); + } + + return op_pc+1; +} + +static int BRANCH_COND_B(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC(CF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); +} + +static int BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + int host_reg; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + if (not) + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_UNKNOWN: + CALL_FUNC(ZF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + break; + } +} + +static int BRANCH_COND_O(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC(VF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); +} + +static int BRANCH_COND_P(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC(PF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); +} + +static int BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + int host_reg; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + AND_HOST_REG_IMM(host_reg, 0x80); + if (not) + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + AND_HOST_REG_IMM(host_reg, 0x8000); + if (not) + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + AND_HOST_REG_IMM(host_reg, 0x80000000); + if (not) + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_UNKNOWN: + CALL_FUNC(NF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + break; + } +} + + +#define ropBRANCH(name, func, not) \ +static uint32_t rop ## name(uint8_t opcode, uint32_t fetchdat, \ + uint32_t op_32, uint32_t op_pc, \ + codeblock_t *block) \ +{ \ + uint32_t offset = fetchdat & 0xff; \ + \ + if (offset & 0x80) \ + offset |= 0xffffff00; \ + \ + func(1, op_pc, offset, not); \ + \ + return op_pc+1; \ +} \ +static uint32_t rop ## name ## _w(uint8_t opcode, \ + uint32_t fetchdat, uint32_t op_32, \ + uint32_t op_pc, codeblock_t *block) \ +{ \ + uint32_t offset = fetchdat & 0xffff; \ + \ + if (offset & 0x8000) \ + offset |= 0xffff0000; \ + \ + func(2, op_pc, offset, not); \ + \ + return op_pc+2; \ +} \ +static uint32_t rop ## name ## _l(uint8_t opcode, \ + uint32_t fetchdat, uint32_t op_32, \ + uint32_t op_pc, codeblock_t *block) \ +{ \ + uint32_t offset = fastreadl(cs + op_pc); \ + \ + func(4, op_pc, offset, not); \ + \ + return op_pc+4; \ +} + +ropBRANCH(JB, BRANCH_COND_B, 0) +ropBRANCH(JNB, BRANCH_COND_B, 1) +ropBRANCH(JE, BRANCH_COND_E, 0) +ropBRANCH(JNE, BRANCH_COND_E, 1) +ropBRANCH(JO, BRANCH_COND_O, 0) +ropBRANCH(JNO, BRANCH_COND_O, 1) +ropBRANCH(JP, BRANCH_COND_P, 0) +ropBRANCH(JNP, BRANCH_COND_P, 1) +ropBRANCH(JS, BRANCH_COND_S, 0) +ropBRANCH(JNS, BRANCH_COND_S, 1) +ropBRANCH(JL, BRANCH_COND_L, 0) +ropBRANCH(JNL, BRANCH_COND_L, 1) +ropBRANCH(JLE, BRANCH_COND_LE, 0) +ropBRANCH(JNLE, BRANCH_COND_LE, 1) +ropBRANCH(JBE, BRANCH_COND_BE, 0) +ropBRANCH(JNBE, BRANCH_COND_BE, 1) diff --git a/src/codegen_ops_logic.h b/src/codegen_ops_logic.h new file mode 100644 index 000000000..02384cd97 --- /dev/null +++ b/src/codegen_ops_logic.h @@ -0,0 +1,507 @@ +#define ROP_LOGIC(name, op, writeback) \ + static uint32_t rop ## name ## _b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_B(fetchdat & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); \ + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_W(fetchdat & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); \ + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_L(fetchdat & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); \ + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_B(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_B(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_W(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_W(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_L(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_L(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } + +ROP_LOGIC(AND, AND, 1) +ROP_LOGIC(OR, OR, 1) +ROP_LOGIC(XOR, XOR, 1) + +static uint32_t ropTEST_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_B(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + dst_reg = TEST_HOST_REG_B(dst_reg, src_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + return op_pc + 1; +} +static uint32_t ropTEST_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + dst_reg = TEST_HOST_REG_W(dst_reg, src_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + return op_pc + 1; +} +static uint32_t ropTEST_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + dst_reg = TEST_HOST_REG_L(dst_reg, src_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + return op_pc + 1; +} + +static uint32_t ropAND_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + AND_HOST_REG_IMM(host_reg, (fetchdat & 0xff) | 0xffffff00); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + return op_pc + 1; +} +static uint32_t ropAND_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + AND_HOST_REG_IMM(host_reg, (fetchdat & 0xffff) | 0xffff0000); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + return op_pc + 2; +} +static uint32_t ropAND_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + AND_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + return op_pc + 4; +} + +static uint32_t ropOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + OR_HOST_REG_IMM(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + return op_pc + 1; +} +static uint32_t ropOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + OR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + return op_pc + 2; +} +static uint32_t ropOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + OR_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + return op_pc + 4; +} + +static uint32_t ropTEST_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + return op_pc + 1; +} +static uint32_t ropTEST_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + return op_pc + 2; +} +static uint32_t ropTEST_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + return op_pc + 4; +} + +static uint32_t ropXOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + XOR_HOST_REG_IMM(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + return op_pc + 1; +} +static uint32_t ropXOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + XOR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + return op_pc + 2; +} +static uint32_t ropXOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + XOR_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + return op_pc + 4; +} + +static uint32_t ropF6(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + uint8_t imm; + + switch (fetchdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_B(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + } + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + imm = fastreadb(cs + op_pc + 1); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + host_reg = 0; + } + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + host_reg = TEST_HOST_REG_IMM(host_reg, imm); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + return op_pc + 2; + + case 0x10: /*NOT b*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + host_reg = LOAD_REG_B(fetchdat & 7); + XOR_HOST_REG_IMM(host_reg, 0xff); + STORE_REG_B_RELEASE(host_reg); + return op_pc + 1; + + case 0x18: /*NEG b*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + host_reg = LOAD_REG_B(fetchdat & 7); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, host_reg); + NEG_HOST_REG_B(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op1, 0); + STORE_REG_B_RELEASE(host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + return op_pc + 1; + } + + return 0; +} +static uint32_t ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + uint16_t imm; + + switch (fetchdat & 0x38) + { + case 0x00: /*TEST w,#*/ + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xffff; + } + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + imm = fastreadw(cs + op_pc + 1); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + host_reg = 0; + } + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + host_reg = TEST_HOST_REG_IMM(host_reg, imm); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + return op_pc + 3; + + case 0x10: /*NOT w*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + host_reg = LOAD_REG_W(fetchdat & 7); + XOR_HOST_REG_IMM(host_reg, 0xffff); + STORE_REG_W_RELEASE(host_reg); + return op_pc + 1; + + case 0x18: /*NEG w*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + host_reg = LOAD_REG_W(fetchdat & 7); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, host_reg); + NEG_HOST_REG_W(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op1, 0); + STORE_REG_W_RELEASE(host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + return op_pc + 1; + } + + return 0; +} +static uint32_t ropF7_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + uint32_t imm; + + switch (fetchdat & 0x38) + { + case 0x00: /*TEST l,#*/ + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_L(fetchdat & 7); + imm = fastreadl(cs + op_pc + 1); + } + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + imm = fastreadl(cs + op_pc + 1); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + host_reg = 0; + } + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + host_reg = TEST_HOST_REG_IMM(host_reg, imm); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + return op_pc + 5; + + case 0x10: /*NOT l*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + host_reg = LOAD_REG_L(fetchdat & 7); + XOR_HOST_REG_IMM(host_reg, 0xffffffff); + STORE_REG_L_RELEASE(host_reg); + return op_pc + 1; + + case 0x18: /*NEG l*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + host_reg = LOAD_REG_L(fetchdat & 7); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, host_reg); + NEG_HOST_REG_L(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op1, 0); + STORE_REG_L_RELEASE(host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + return op_pc + 1; + } + + return 0; +} diff --git a/src/codegen_ops_misc.h b/src/codegen_ops_misc.h new file mode 100644 index 000000000..7ed3ceeb9 --- /dev/null +++ b/src/codegen_ops_misc.h @@ -0,0 +1,115 @@ +static uint32_t ropNOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + return op_pc; +} + +static uint32_t ropCLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + CLEAR_BITS((uintptr_t)&flags, D_FLAG); + return op_pc; +} +static uint32_t ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + SET_BITS((uintptr_t)&flags, D_FLAG); + return op_pc; +} + +static uint32_t codegen_temp; +static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + if ((fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20)// && (fetchdat & 0x38) != 0x30) + return 0; + + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + host_reg = 0; + } + + switch (fetchdat & 0x38) + { + case 0x10: /*CALL*/ + STORE_HOST_REG_ADDR_W((uintptr_t)&codegen_temp, host_reg); + RELEASE_REG(host_reg); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(op_pc + 1); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + host_reg = LOAD_VAR_W((uintptr_t)&codegen_temp); + STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x20: /*JMP*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x30: /*PUSH*/ + if (!host_reg) + host_reg = LOAD_HOST_REG(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + return op_pc + 1; + } +} +static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + if ((fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20)// && (fetchdat & 0x38) != 0x30) + return 0; + + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + host_reg = 0; + } + + switch (fetchdat & 0x38) + { + case 0x10: /*CALL*/ + STORE_HOST_REG_ADDR((uintptr_t)&codegen_temp, host_reg); + RELEASE_REG(host_reg); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(op_pc + 1); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + host_reg = LOAD_VAR_L((uintptr_t)&codegen_temp); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x20: /*JMP*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x30: /*PUSH*/ + if (!host_reg) + host_reg = LOAD_HOST_REG(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + return op_pc + 1; + } +} diff --git a/src/codegen_ops_mmx.h b/src/codegen_ops_mmx.h new file mode 100644 index 000000000..9d8b49c84 --- /dev/null +++ b/src/codegen_ops_mmx.h @@ -0,0 +1,277 @@ +static uint32_t ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg1, host_reg2; + + MMX_ENTER(); + + LOAD_MMX_Q((fetchdat >> 3) & 7, &host_reg1, &host_reg2); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_MMX_Q(fetchdat & 7, host_reg1, host_reg2); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 7); + + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); + } + + return op_pc + 1; +} + +static uint32_t ropMOVQ_mm_q(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + MMX_ENTER(); + + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg1, host_reg2; + + LOAD_MMX_Q(fetchdat & 7, &host_reg1, &host_reg2); + STORE_MMX_Q((fetchdat >> 3) & 7, host_reg1, host_reg2); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_Q(target_seg); + STORE_MMX_Q((fetchdat >> 3) & 7, LOAD_Q_REG_1, LOAD_Q_REG_2); + } + + return op_pc + 1; +} + +static uint32_t ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + MMX_ENTER(); + + host_reg = LOAD_MMX_D((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 3); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + } + + return op_pc + 1; +} +static uint32_t ropMOVD_mm_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + MMX_ENTER(); + + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_L(fetchdat & 7); + STORE_MMX_LQ((fetchdat >> 3) & 7, host_reg); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_L(target_seg); + STORE_MMX_LQ((fetchdat >> 3) & 7, 0); + } + + return op_pc + 1; +} + +#define MMX_OP(name, func) \ +static uint32_t name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int src_reg1, src_reg2; \ + int xmm_src, xmm_dst; \ + \ + MMX_ENTER(); \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + xmm_src = LOAD_MMX_Q_MMX(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + \ + MEM_LOAD_ADDR_EA_Q(target_seg); \ + src_reg1 = LOAD_Q_REG_1; \ + src_reg2 = LOAD_Q_REG_2; \ + xmm_src = LOAD_INT_TO_MMX(src_reg1, src_reg2); \ + } \ + xmm_dst = LOAD_MMX_Q_MMX((fetchdat >> 3) & 7); \ + func(xmm_dst, xmm_src); \ + STORE_MMX_Q_MMX((fetchdat >> 3) & 7, xmm_dst); \ + \ + return op_pc + 1; \ +} + +MMX_OP(ropPAND, MMX_AND) +MMX_OP(ropPANDN, MMX_ANDN) +MMX_OP(ropPOR, MMX_OR) +MMX_OP(ropPXOR, MMX_XOR) + +MMX_OP(ropPADDB, MMX_ADDB) +MMX_OP(ropPADDW, MMX_ADDW) +MMX_OP(ropPADDD, MMX_ADDD) +MMX_OP(ropPADDSB, MMX_ADDSB) +MMX_OP(ropPADDSW, MMX_ADDSW) +MMX_OP(ropPADDUSB, MMX_ADDUSB) +MMX_OP(ropPADDUSW, MMX_ADDUSW) + +MMX_OP(ropPSUBB, MMX_SUBB) +MMX_OP(ropPSUBW, MMX_SUBW) +MMX_OP(ropPSUBD, MMX_SUBD) +MMX_OP(ropPSUBSB, MMX_SUBSB) +MMX_OP(ropPSUBSW, MMX_SUBSW) +MMX_OP(ropPSUBUSB, MMX_SUBUSB) +MMX_OP(ropPSUBUSW, MMX_SUBUSW) + +MMX_OP(ropPUNPCKLBW, MMX_PUNPCKLBW); +MMX_OP(ropPUNPCKLWD, MMX_PUNPCKLWD); +MMX_OP(ropPUNPCKLDQ, MMX_PUNPCKLDQ); +MMX_OP(ropPACKSSWB, MMX_PACKSSWB); +MMX_OP(ropPCMPGTB, MMX_PCMPGTB); +MMX_OP(ropPCMPGTW, MMX_PCMPGTW); +MMX_OP(ropPCMPGTD, MMX_PCMPGTD); +MMX_OP(ropPACKUSWB, MMX_PACKUSWB); +MMX_OP(ropPUNPCKHBW, MMX_PUNPCKHBW); +MMX_OP(ropPUNPCKHWD, MMX_PUNPCKHWD); +MMX_OP(ropPUNPCKHDQ, MMX_PUNPCKHDQ); +MMX_OP(ropPACKSSDW, MMX_PACKSSDW); + +MMX_OP(ropPCMPEQB, MMX_PCMPEQB); +MMX_OP(ropPCMPEQW, MMX_PCMPEQW); +MMX_OP(ropPCMPEQD, MMX_PCMPEQD); + +MMX_OP(ropPSRLW, MMX_PSRLW) +MMX_OP(ropPSRLD, MMX_PSRLD) +MMX_OP(ropPSRLQ, MMX_PSRLQ) +MMX_OP(ropPSRAW, MMX_PSRAW) +MMX_OP(ropPSRAD, MMX_PSRAD) +MMX_OP(ropPSLLW, MMX_PSLLW) +MMX_OP(ropPSLLD, MMX_PSLLD) +MMX_OP(ropPSLLQ, MMX_PSLLQ) + +MMX_OP(ropPMULLW, MMX_PMULLW); +MMX_OP(ropPMULHW, MMX_PMULHW); +MMX_OP(ropPMADDWD, MMX_PMADDWD); + +static uint32_t ropPSxxW_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int xmm_dst; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + return 0; + + MMX_ENTER(); + + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + { + case 0x10: /*PSRLW*/ + MMX_PSRLW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x20: /*PSRAW*/ + MMX_PSRAW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x30: /*PSLLW*/ + MMX_PSLLW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + } + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); + + return op_pc + 2; +} +static uint32_t ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int xmm_dst; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + return 0; + + MMX_ENTER(); + + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + { + case 0x10: /*PSRLD*/ + MMX_PSRLD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x20: /*PSRAD*/ + MMX_PSRAD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x30: /*PSLLD*/ + MMX_PSLLD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + } + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); + + return op_pc + 2; +} +static uint32_t ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int xmm_dst; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + return 0; + + MMX_ENTER(); + + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + { + case 0x10: /*PSRLQ*/ + MMX_PSRLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x20: /*PSRAQ*/ + MMX_PSRAQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x30: /*PSLLQ*/ + MMX_PSLLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + } + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); + + return op_pc + 2; +} + +static uint32_t ropEMMS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + codegen_mmx_entered = 0; + + return 0; +} diff --git a/src/codegen_ops_mov.h b/src/codegen_ops_mov.h new file mode 100644 index 000000000..ea1dfd006 --- /dev/null +++ b/src/codegen_ops_mov.h @@ -0,0 +1,506 @@ +static uint32_t ropMOV_rb_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_REG_B(opcode & 7, fetchdat & 0xff); + + return op_pc + 1; +} +static uint32_t ropMOV_rw_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_REG_W(opcode & 7, fetchdat & 0xffff); + + return op_pc + 2; +} +static uint32_t ropMOV_rl_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + fetchdat = fastreadl(cs + op_pc); + + STORE_IMM_REG_L(opcode & 7, fetchdat); + + return op_pc + 4; +} + + +static uint32_t ropMOV_b_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_B_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 0); + + MEM_STORE_ADDR_EA_B(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 1; +} +static uint32_t ropMOV_w_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_W_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 1); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 1; +} + +static uint32_t ropMOV_l_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + host_reg = LOAD_REG_L((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 3); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + RELEASE_REG(host_reg); + + } + + return op_pc + 1; +} + +static uint32_t ropMOV_r_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + STORE_REG_TARGET_B_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + STORE_REG_TARGET_B_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOV_r_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_W(fetchdat & 7); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOV_r_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_L(fetchdat & 7); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_L(target_seg); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} + +static uint32_t ropMOV_b_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_IMM_REG_B(fetchdat & 7, (fetchdat >> 8) & 0xff); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + uint32_t imm = fastreadb(cs + op_pc + 1); + int host_reg = LOAD_REG_IMM(imm); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_B(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 2; +} +static uint32_t ropMOV_w_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_IMM_REG_W(fetchdat & 7, (fetchdat >> 8) & 0xffff); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + uint32_t imm = fastreadw(cs + op_pc + 1); + int host_reg = LOAD_REG_IMM(imm); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 3; +} +static uint32_t ropMOV_l_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + uint32_t imm = fastreadl(cs + op_pc + 1); + + STORE_IMM_REG_L(fetchdat & 7, imm); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + uint32_t imm = fastreadl(cs + op_pc + 1); + int host_reg = LOAD_REG_IMM(imm); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 5; +} + + +static uint32_t ropMOV_AL_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_READ(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + MEM_LOAD_ADDR_IMM_B(op_ea_seg, addr); + STORE_REG_TARGET_B_RELEASE(0, REG_AL); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_AX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_READ(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + MEM_LOAD_ADDR_IMM_W(op_ea_seg, addr); + STORE_REG_TARGET_W_RELEASE(0, REG_AX); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_EAX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_READ(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + MEM_LOAD_ADDR_IMM_L(op_ea_seg, addr); + STORE_REG_TARGET_L_RELEASE(0, REG_EAX); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +static uint32_t ropMOV_a_AL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + int host_reg; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_WRITE(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + host_reg = LOAD_REG_B(REG_AL); + + MEM_STORE_ADDR_IMM_B(op_ea_seg, addr, host_reg); + RELEASE_REG(host_reg); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_a_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + int host_reg; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_WRITE(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + host_reg = LOAD_REG_W(REG_AX); + + MEM_STORE_ADDR_IMM_W(op_ea_seg, addr, host_reg); + RELEASE_REG(host_reg); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_a_EAX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + int host_reg; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_WRITE(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + host_reg = LOAD_REG_L(REG_EAX); + + MEM_STORE_ADDR_IMM_L(op_ea_seg, addr, host_reg); + RELEASE_REG(host_reg); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +static uint32_t ropLEA_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_REG_TARGET_W_RELEASE(0, dest_reg); + + return op_pc + 1; +} +static uint32_t ropLEA_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_REG_TARGET_L_RELEASE(0, dest_reg); + + return op_pc + 1; +} + +static uint32_t ropMOVZX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = ZERO_EXTEND_W_B(host_reg); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + ZERO_EXTEND_W_B(0); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVZX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = ZERO_EXTEND_L_B(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + ZERO_EXTEND_L_B(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVZX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_W(fetchdat & 7); + host_reg = ZERO_EXTEND_L_W(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + ZERO_EXTEND_L_W(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} + +static uint32_t ropMOVSX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = SIGN_EXTEND_W_B(host_reg); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + SIGN_EXTEND_W_B(0); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVSX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = SIGN_EXTEND_L_B(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + SIGN_EXTEND_L_B(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVSX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_W(fetchdat & 7); + host_reg = SIGN_EXTEND_L_W(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + SIGN_EXTEND_L_W(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} diff --git a/src/codegen_ops_shift.h b/src/codegen_ops_shift.h new file mode 100644 index 000000000..cedcf0c44 --- /dev/null +++ b/src/codegen_ops_shift.h @@ -0,0 +1,114 @@ +#define SHIFT(size, size2, count, res_store) \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, count); \ + reg = LOAD_REG_ ## size(fetchdat & 7); \ + res_store((uint32_t)&cpu_state.flags_op1, reg); \ + \ + switch (fetchdat & 0x38) \ + { \ + case 0x20: case 0x30: /*SHL*/ \ + SHL_ ## size ## _IMM(reg, count); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SHL ## size2); \ + break; \ + \ + case 0x28: /*SHR*/ \ + SHR_ ## size ## _IMM(reg, count); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SHR ## size2); \ + break; \ + \ + case 0x38: /*SAR*/ \ + SAR_ ## size ## _IMM(reg, count); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SAR ## size2); \ + break; \ + } \ + \ + res_store((uint32_t)&cpu_state.flags_res, reg); \ + STORE_REG_ ## size ## _RELEASE(reg); + +static uint32_t ropC0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int count; + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + count = (fetchdat >> 8) & 0x1f; + + SHIFT(B, 8, count, STORE_HOST_REG_ADDR_BL); + + return op_pc + 2; +} +static uint32_t ropC1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int count; + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + count = (fetchdat >> 8) & 0x1f; + + SHIFT(W, 16, count, STORE_HOST_REG_ADDR_WL); + + return op_pc + 2; +} +static uint32_t ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int count; + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + count = (fetchdat >> 8) & 0x1f; + + SHIFT(L, 32, count, STORE_HOST_REG_ADDR); + + return op_pc + 2; +} + +static uint32_t ropD0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(B, 8, 1, STORE_HOST_REG_ADDR_BL); + + return op_pc + 1; +} +static uint32_t ropD1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(W, 16, 1, STORE_HOST_REG_ADDR_WL); + + return op_pc + 1; +} +static uint32_t ropD1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(L, 32, 1, STORE_HOST_REG_ADDR); + + return op_pc + 1; +} diff --git a/src/codegen_ops_stack.h b/src/codegen_ops_stack.h new file mode 100644 index 000000000..d0c943d16 --- /dev/null +++ b/src/codegen_ops_stack.h @@ -0,0 +1,250 @@ +static uint32_t ropPUSH_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_W(opcode & 7); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + return op_pc; +} +static uint32_t ropPUSH_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_L(opcode & 7); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + return op_pc; +} + +static uint32_t ropPUSH_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t imm = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + return op_pc+2; +} +static uint32_t ropPUSH_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t imm = fastreadl(cs + op_pc); + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + return op_pc+4; +} + +static uint32_t ropPUSH_imm_b16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t imm = fetchdat & 0xff; + int host_reg; + + if (imm & 0x80) + imm |= 0xff00; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + return op_pc+1; +} +static uint32_t ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t imm = fetchdat & 0xff; + int host_reg; + + if (imm & 0x80) + imm |= 0xffffff00; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + return op_pc+1; +} + +static uint32_t ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + SP_MODIFY(2); + STORE_REG_TARGET_W_RELEASE(0, opcode & 7); + + return op_pc; +} +static uint32_t ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + SP_MODIFY(4); + STORE_REG_TARGET_L_RELEASE(0, opcode & 7); + + return op_pc; +} + +static uint32_t ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(2); + + return -1; +} +static uint32_t ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(4); + + return -1; +} + +static uint32_t ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(2+offset); + + return -1; +} +static uint32_t ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(4+offset); + + return -1; +} + +static uint32_t ropCALL_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(op_pc+2); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); + + return -1; +} +static uint32_t ropCALL_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fastreadl(cs + op_pc); + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(op_pc+4); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); + + return -1; +} + +static uint32_t ropLEAVE_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_EBP_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + host_reg = LOAD_REG_W(REG_BP); /*SP = BP + 2*/ + ADD_HOST_REG_IMM_W(host_reg, 2); + STORE_REG_TARGET_W_RELEASE(host_reg, REG_SP); + STORE_REG_TARGET_W_RELEASE(0, REG_BP); /*BP = POP_W()*/ + + return op_pc; +} +static uint32_t ropLEAVE_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_EBP_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + host_reg = LOAD_REG_L(REG_EBP); /*ESP = EBP + 4*/ + ADD_HOST_REG_IMM(host_reg, 4); + STORE_REG_TARGET_L_RELEASE(host_reg, REG_ESP); + STORE_REG_TARGET_L_RELEASE(0, REG_EBP); /*EBP = POP_L()*/ + + return op_pc; +} + +#define ROP_PUSH_SEG(seg) \ +static uint32_t ropPUSH_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int host_reg; \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(-2); \ + host_reg = LOAD_VAR_W((uintptr_t)&seg); \ + MEM_STORE_ADDR_EA_W(&_ss, host_reg); \ + SP_MODIFY(-2); \ + \ + return op_pc; \ +} \ +static uint32_t ropPUSH_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int host_reg; \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(-4); \ + host_reg = LOAD_VAR_W((uintptr_t)&seg); \ + MEM_STORE_ADDR_EA_L(&_ss, host_reg); \ + SP_MODIFY(-4); \ + \ + return op_pc; \ +} + +ROP_PUSH_SEG(CS) +ROP_PUSH_SEG(DS) +ROP_PUSH_SEG(ES) +ROP_PUSH_SEG(SS) diff --git a/src/codegen_ops_x86-64.h b/src/codegen_ops_x86-64.h new file mode 100644 index 000000000..173acd222 --- /dev/null +++ b/src/codegen_ops_x86-64.h @@ -0,0 +1,4734 @@ +/*Register allocation : + R8-R15 - emulated registers +*/ + +#define HOST_REG_XMM_START 0 +#define HOST_REG_XMM_END 7 +static inline int find_host_xmm_reg() +{ + int c; + for (c = HOST_REG_XMM_START; c < HOST_REG_XMM_END; c++) + { + if (host_reg_xmm_mapping[c] == -1) + break; + } + + if (c == HOST_REG_XMM_END) + fatal("Out of host XMM regs!\n"); + return c; +} +static void call(codeblock_t *block, uintptr_t func) +{ + // uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5]; + intptr_t diff = func - (intptr_t)&block->data[block_pos + 5]; + + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + if (diff >= -0x80000000 && diff < 0x7fffffff) + { + addbyte(0xE8); /*CALL*/ + addlong((uint32_t)diff); + } + else + { + addbyte(0x48); /*MOV RAX, func*/ + addbyte(0xb8); + addquad(func); + addbyte(0xff); /*CALL RAX*/ + addbyte(0xd0); + } +} + +static void call_long(uintptr_t func) +{ + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + addbyte(0x48); /*MOV RAX, func*/ + addbyte(0xb8); + addquad(func); + addbyte(0xff); /*CALL RAX*/ + addbyte(0xd0); +} + +static void load_param_1_32(codeblock_t *block, uint32_t param) +{ +#if WIN64 + addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ +#else + addbyte(0xbf); /*MOVL $fetchdat,%edi*/ +#endif + addlong(param); +} +static void load_param_1_reg_32(int reg) +{ +#if WIN64 + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc0 | REG_ECX | (reg << 3)); +#else + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV EDI, EAX*/ + addbyte(0xc0 | REG_EDI | (reg << 3)); +#endif +} +static void load_param_1_64(codeblock_t *block, uint64_t param) +{ + addbyte(0x48); +#if WIN64 + addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ +#else + addbyte(0xbf); /*MOVL $fetchdat,%edi*/ +#endif + addquad(param); +} + +static void load_param_2_32(codeblock_t *block, uint32_t param) +{ +#if WIN64 + addbyte(0xba); /*MOVL $fetchdat,%edx*/ +#else + addbyte(0xbe); /*MOVL $fetchdat,%esi*/ +#endif + addlong(param); +} +static void load_param_2_reg_32(int reg) +{ +#if WIN64 + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV EDX, EAX*/ + addbyte(0xc0 | REG_EDX | (reg << 3)); +#else + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV ESI, EAX*/ + addbyte(0xc0 | REG_ESI | (reg << 3)); +#endif +} +static void load_param_2_64(codeblock_t *block, uint64_t param) +{ + addbyte(0x48); +#if WIN64 + addbyte(0xba); /*MOVL $fetchdat,%edx*/ +#else + addbyte(0xbe); /*MOVL $fetchdat,%esi*/ +#endif + addquad(param); +} + +static void load_param_3_reg_32(int reg) +{ + if (reg & 8) + { +#if WIN64 + addbyte(0x45); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x44); /*MOV EDX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | (reg << 3)); +#endif + } + else + { +#if WIN64 + addbyte(0x41); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x90); + addbyte(0x89); /*MOV EDX, reg*/ + addbyte(0xc0 | REG_EDX | (reg << 3)); +#endif + } +} +static void load_param_3_reg_64(int reg) +{ + if (reg & 8) + { +#if WIN64 + addbyte(0x4d); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x4c); /*MOVL EDX,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((reg & 7) << 3)); +#endif + } + else + { +#if WIN64 + addbyte(0x49); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x48); /*MOVL EDX,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((reg & 7) << 3)); +#endif + } +} + +static void CALL_FUNC(uintptr_t func) +{ + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + addbyte(0x48); /*MOV RAX, func*/ + addbyte(0xb8); + addquad(func); + addbyte(0xff); /*CALL RAX*/ + addbyte(0xd0); +} + +static void RELEASE_REG(int host_reg) +{ +} + +static int LOAD_REG_B(int reg) +{ + int host_reg = reg & 3; +// host_reg_mapping[host_reg] = reg; + + if (!codegen_reg_loaded[reg & 3]) + { + addbyte(0x44); /*MOVZX W[reg],host_reg*/ + addbyte(0x8b); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 3].b - (uint32_t)&EAX); + } + + codegen_reg_loaded[reg & 3] = 1; + + if (reg & 4) + return host_reg | 0x18; + + return host_reg | 8; +} +static int LOAD_REG_W(int reg) +{ + int host_reg = reg; +// host_reg_mapping[host_reg] = reg; + + if (!codegen_reg_loaded[reg & 7]) + { + addbyte(0x44); /*MOVZX W[reg],host_reg*/ + addbyte(0x8b); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].w - (uint32_t)&EAX); + } + + codegen_reg_loaded[reg & 7] = 1; + + return host_reg | 8; +} +static int LOAD_REG_L(int reg) +{ + int host_reg = reg; +// host_reg_mapping[host_reg] = reg; + + if (!codegen_reg_loaded[reg & 7]) + { + addbyte(0x44); /*MOVZX W[reg],host_reg*/ + addbyte(0x8b); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].l - (uint32_t)&EAX); + } + + codegen_reg_loaded[reg & 7] = 1; + + return host_reg | 8; +} + +static int LOAD_REG_IMM(uint32_t imm) +{ + int host_reg = REG_EBX; + + addbyte(0xb8 | REG_EBX); /*MOVL EBX, imm*/ + addlong(imm); + + return host_reg; +} + +static void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) +{ + int dest_reg = LOAD_REG_L(guest_reg & 3) & 7; + + if (guest_reg & 4) + { + if (host_reg & 8) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); + if (host_reg & 0x10) + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + else + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(0x08); + } + } + else + { + if (host_reg) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); + } + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(0x08); + } + addbyte(0x66); /*AND dest_reg, 0x00ff*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xe0 | dest_reg); + addword(0x00ff); + addbyte(0x66); /*OR dest_reg, AX*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | dest_reg); + addbyte(0x66); /*MOVW regs[guest_reg].w, dest_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | (dest_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].w - (uint32_t)&EAX); + } + else + { + if (host_reg & 8) + { + if (host_reg & 0x10) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x41); /*MOV dest_reg, AL*/ + addbyte(0x88); + addbyte(0xc0 | (dest_reg & 7)); + addbyte(0x88); /*MOVB regs[reg].b, AH*/ + addbyte(0x65); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b - (uint32_t)&EAX); + } + else + { + addbyte(0x45); /*MOVB dest_reg, host_reg*/ + addbyte(0x88); + addbyte(0xc0 | (dest_reg & 7) | ((host_reg & 7) << 3)); + addbyte(0x44); /*MOVB regs[guest_reg].b, host_reg*/ + addbyte(0x88); + addbyte(0x45 | ((host_reg & 3) << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b - (uint32_t)&EAX); + } + } + else + { + if (host_reg & 0x10) + { + addbyte(0xc1); /*SHR host_reg, 8*/ + addbyte(0xe8 | (host_reg & 7)); + addbyte(8); + } + addbyte(0x41); /*MOVB dest_reg, host_reg*/ + addbyte(0x88); + addbyte(0xc0 | (dest_reg & 7) | ((host_reg & 7) << 3)); + addbyte(0x88); /*MOVB regs[guest_reg].b, host_reg*/ + addbyte(0x45 | ((host_reg & 3) << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b - (uint32_t)&EAX); + } + } +} +static void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) +{ + int dest_reg = LOAD_REG_L(guest_reg & 7) & 7; + + if (host_reg & 8) + { + addbyte(0x66); /*MOVW guest_reg, host_reg*/ + addbyte(0x45); + addbyte(0x89); + addbyte(0xc0 | dest_reg | ((host_reg & 7) << 3)); + addbyte(0x66); /*MOVW regs[guest_reg].w, host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].w - (uint32_t)&EAX); + } + else + { + addbyte(0x66); /*MOVW guest_reg, host_reg*/ + addbyte(0x41); + addbyte(0x89); + addbyte(0xc0 | dest_reg | (host_reg << 3)); + addbyte(0x66); /*MOVW regs[guest_reg].w, host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].w - (uint32_t)&EAX); + } +} +static void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) +{ + if (host_reg & 8) + { + addbyte(0x45); /*MOVL guest_reg, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | guest_reg | (host_reg << 3)); + addbyte(0x44); /*MOVL regs[guest_reg].l, host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].l - (uint32_t)&EAX); + } + else + { + addbyte(0x41); /*MOVL guest_reg, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | guest_reg | (host_reg << 3)); + addbyte(0x89); /*MOVL regs[guest_reg].l, host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].l - (uint32_t)&EAX); + } +} + +static void STORE_REG_B_RELEASE(int host_reg) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*MOVW [reg],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 7].w - (uint32_t)&EAX); + } + else + { + addbyte(0x44); /*MOVB [reg],host_reg*/ + addbyte(0x88); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 7].b - (uint32_t)&EAX); + } +} +static void STORE_REG_W_RELEASE(int host_reg) +{ + addbyte(0x66); /*MOVW [reg],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 7].w - (uint32_t)&EAX); +} +static void STORE_REG_L_RELEASE(int host_reg) +{ + addbyte(0x44); /*MOVL [reg],host_reg*/ + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 7].l - (uint32_t)&EAX); +} + +static void STORE_IMM_REG_B(int reg, uint8_t val) +{ + if (reg & 4) + { + int host_reg = LOAD_REG_W(reg & 3) & 7; + addbyte(0x66); /*AND host_reg, 0x00ff*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xe0 | host_reg); + addword(0x00ff); + addbyte(0x66); /*OR host_reg, val << 8*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xc8 | host_reg); + addword(val << 8); + addbyte(0x66); /*MOVW host_reg, regs[host_reg].w*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 3].w - (uint32_t)&EAX); + } + else + { + addbyte(0x41); /*MOVB reg, imm*/ + addbyte(0xb0 | reg); + addbyte(val); + addbyte(0x44); /*MOVB reg, regs[reg].b*/ + addbyte(0x88); + addbyte(0x45 | (reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].b - (uint32_t)&EAX); + } +} +static void STORE_IMM_REG_W(int reg, uint16_t val) +{ + addbyte(0x66); /*MOVW reg, imm*/ + addbyte(0x41); + addbyte(0xb8 | reg); + addword(val); + addbyte(0x66); /*MOVW reg, regs[reg].w*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | (reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].w - (uint32_t)&EAX); +} +static void STORE_IMM_REG_L(int reg, uint32_t val) +{ + addbyte(0x41); /*MOVL reg, imm*/ + addbyte(0xb8 | reg); + addlong(val); + addbyte(0x44); /*MOVL reg, regs[reg].l*/ + addbyte(0x89); + addbyte(0x45 | (reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].l - (uint32_t)&EAX); +} + +static void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) +{ + if (addr < 0x100000000) + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x04); + addbyte(0x25); + addlong(addr); + addlong(val); + } + else + { + fatal("addr > 32-bit\n"); + } +} + + + + +static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + int mod = (fetchdat >> 6) & 3; + int reg = (fetchdat >> 3) & 7; + int rm = fetchdat & 7; + + if (!mod && rm == 6) + { + addbyte(0xb8); /*MOVL EAX, imm*/ + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + int base_reg, index_reg; + + switch (rm) + { + case 0: case 1: case 7: + base_reg = LOAD_REG_W(REG_BX); + break; + case 2: case 3: case 6: + base_reg = LOAD_REG_W(REG_BP); + break; + case 4: + base_reg = LOAD_REG_W(REG_SI); + break; + case 5: + base_reg = LOAD_REG_W(REG_DI); + break; + } + if (!(rm & 4)) + { + if (rm & 1) + index_reg = LOAD_REG_W(REG_DI); + else + index_reg = LOAD_REG_W(REG_SI); + } + base_reg &= 7; + index_reg &= 7; + + switch (mod) + { + case 0: + if (rm & 4) + { + addbyte(0x41); /*MOVZX EAX, base_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xc0 | base_reg); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3)); + } + } + break; + case 1: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm8*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte((fetchdat >> 8) & 0xff); + } + (*op_pc)++; + break; + case 2: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong((fetchdat >> 8) & 0xffff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm16*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3)); + addlong((fetchdat >> 8) & 0xffff); + } + (*op_pc) += 2; + break; + + } + if (mod || !(rm & 4)) + { + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + } + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} +static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + int mod = (fetchdat >> 6) & 3; + int reg = (fetchdat >> 3) & 7; + int rm = fetchdat & 7; + uint32_t new_eaaddr; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + int base_reg = -1, index_reg = -1; + + (*op_pc)++; + + if (mod || (sib & 7) != 5) + base_reg = LOAD_REG_L(sib & 7) & 7; + + if (((sib >> 3) & 7) != 4) + index_reg = LOAD_REG_L((sib >> 3) & 7) & 7; + + if (index_reg == -1) + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOV EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x44); + addbyte(0x24); + } + else + { + addbyte(0x40 | base_reg); + } + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x84); + addbyte(0x24); + } + else + { + addbyte(0x80 | base_reg); + } + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + else + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + if (sib >> 6) + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*scale*/ + addbyte(0x42); + addbyte(0x8d); + addbyte(0x04); + addbyte(0x05 | (sib & 0xc0) | (index_reg << 3)); + addlong(new_eaaddr); + } + else + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | index_reg); + addlong(new_eaaddr); + } + (*op_pc) += 4; + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + } + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + addbyte(0x05); + addlong(stack_offset); + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + } + else + { + int base_reg; + + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, new_eaaddr*/ + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + base_reg = LOAD_REG_L(rm) & 7; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, base_reg+imm32*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong(new_eaaddr); + (*op_pc) += 4; + } + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + } + return op_ea_seg; +} + +static x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) +{ + if (op_32 & 0x200) + return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); + return FETCH_EA_16(op_ea_seg, fetchdat, op_ssegs, op_pc); +} + + + +static void CHECK_SEG_READ(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); /*JE end*/ + addbyte(0x84); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static void CHECK_SEG_WRITE(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); /*JE end*/ + addbyte(0x84); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) +{ + addbyte(0x3b); /*CMP EAX, seg->limit_low*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&seg->limit_low); + addbyte(0x0f); /*JB BLOCK_GPF_OFFSET*/ + addbyte(0x82); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + if (end_offset) + { + addbyte(0x83); /*ADD EAX, end_offset*/ + addbyte(0xc0); + addbyte(end_offset); + addbyte(0x3b); /*CMP EAX, seg->limit_high*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&seg->limit_high); + addbyte(0x0f); /*JNBE BLOCK_GPF_OFFSET*/ + addbyte(0x87); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + addbyte(0x83); /*SUB EAX, end_offset*/ + addbyte(0xe8); + addbyte(end_offset); + } +} + +#define IS_32_ADDR(x) !(((uintptr_t)x) & 0xffffffff00000000) + +static void MEM_LOAD_ADDR_EA_B(x86seg *seg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2); + addbyte(0x8b); /*MOV AL,[RDI+RSI]*/ + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long(readmemb386l); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_LOAD_ADDR_EA_W(x86seg *seg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 1[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x01); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xc7); + addlong(0xfff); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + addbyte(0x66); /*MOV AX,-1[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x44); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-1); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long(readmemwl); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_LOAD_ADDR_EA_L(x86seg *seg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 3[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x03); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xc7); + addlong(0xffc); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x8b); /*MOV EAX,-3[RDI+RSI]*/ + addbyte(0x44); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-3); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long(readmemll); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 7[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x07); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xc7); + addlong(0xff8); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + addbyte(0x48); /*MOV RAX,-7[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x44); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long(readmemql); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} + +static void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_B(seg); +} +static void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_W(seg); +} +static void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_L(seg); +} + +static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) +{ + if (host_reg & 0x10) + { + /*Handle high byte of register*/ + if (host_reg & 8) + { + addbyte(0x45); /*MOVL R8, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*MOVL R8, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3)); + } + addbyte(0x66); /*SHR R8, 8*/ + addbyte(0x41); + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + host_reg = 8; + } + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 4:3)+2); + if (host_reg & 8) + { + addbyte(0x44); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x88); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x88); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long(writememb386l); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 1[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x01); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xc7); + addlong(0xfff); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 6:5)+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 6:5)+2); + if (host_reg & 8) + { + addbyte(0x66); /*MOV -1[RDI+RSI],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-1); + } + else + { + addbyte(0x66); /*MOV -1[RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-1); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long(writememwl); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 3[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x03); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xc7); + addlong(0xffc); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 5:4)+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 5:4)+2); + if (host_reg & 8) + { + addbyte(0x44); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-3); + } + else + { + addbyte(0x89); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-3); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long(writememll); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 7[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x07); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xc7); + addlong(0xff8); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + if (host_reg & 8) + { + addbyte(0x4c); /*MOV -7[RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7); + } + else + { + addbyte(0x48); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_64(host_reg); + call_long(writememql); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} + +static void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_B(seg, host_reg); +} +static void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_W(seg, host_reg); +} +static void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_L(seg, host_reg); +} + +static void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) +{ + if (host_reg & 0x10) + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX EBX, host_reg*/ + addbyte(0xb7); + addbyte(0xc0 | (REG_ECX << 3) | (host_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xe8 | REG_ECX); + addbyte(8); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX EBX, host_reg*/ + addbyte(0xb6); + addbyte(0xc0 | (REG_ECX << 3) | (host_reg & 7)); + } + addbyte(0x89); /*MOV addr, EBX*/ + addbyte(0x04 | (REG_ECX << 3)); + addbyte(0x25); + addlong(addr); +} +static void STORE_HOST_REG_ADDR_WL(uintptr_t addr, int host_reg) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX ECX, host_reg*/ + addbyte(0xb7); + addbyte(0xc0 | (REG_ECX << 3) | (host_reg & 7)); + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0x89); /*MOV addr, ECX*/ + addbyte(0x45 | (REG_ECX << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + addbyte(0x89); /*MOV addr, ECX*/ + addbyte(0x04 | (REG_ECX << 3)); + addbyte(0x25); + addlong(addr); + } +} +static void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0x66); /*MOVW [addr],host_reg*/ + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + addbyte(0x66); + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL addr,host_reg*/ + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(0x25); + addlong(addr); + } +} +static void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL [addr],host_reg*/ + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL addr,host_reg*/ + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(0x25); + addlong(addr); + } +} + +static void AND_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + addbyte(0x66); /*OR AX, 0x00ff*/ + addbyte(0x0d); + addword(0xff); + addbyte(0x66); /*ANDW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*ANDB dst_reg, AL*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*OR src_reg, 0xff*/ + addbyte(0x81); + addbyte(0xc8 | src_reg); + addword(0xff); + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x41); /*MOVZX EBX, src_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x20); /*ANDB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x44); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x0f); /*MOVZX EBX, src_reg*/ + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x20); /*ANDB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x20); /*ANDB dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } +#if 0 + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + if (src_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*OR src_reg, 0xff*/ + addbyte(0x81); + addbyte(0xc8 | src_reg); + addword(0xff); + } + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (src_reg & 0x10) + { + addbyte(0x66); /*OR src_reg, 0xff*/ + addbyte(0x81); + addbyte(0xc8 | src_reg); + addword(0xff); + } + if (src_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*OR src_reg, 0xff*/ + addbyte(0x81); + addbyte(0xc8 | src_reg); + addword(0xff); + } + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + fatal("!(dst_reg & src_reg & 8) b %i %i\n", dst_reg, src_reg); +#endif +} +static void AND_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x44); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static void AND_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*ANDL dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*ANDL dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x44); /*ANDL dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x21); /*ANDL dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static void AND_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ANDW host_reg, imm<<8*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xe0 | (host_reg & 7)); + addword((imm << 8) | 0xff); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); /*ANDL host_reg, imm*/ + addbyte(0xe0 | (host_reg & 7)); + addlong(imm); + } +} + +static int TEST_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = (dst_reg & 0x10) | REG_EDX; + } + + AND_HOST_REG_B(dst_reg, src_reg); + + return dst_reg & ~0x10; +} +static int TEST_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + AND_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + AND_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((host_reg & 7) << 3)); + host_reg = REG_EDX | (host_reg & 0x10); + } + if (host_reg & 0x10) + { + addbyte(0x66); /*ANDW host_reg, imm<<8*/ + addbyte(0x81); + addbyte(0xe0 | (host_reg & 7)); + addword((imm << 8) | 0xff); + } + else + { + addbyte(0x81); /*ANDL host_reg, imm*/ + addbyte(0xe0 | (host_reg & 7)); + addlong(imm); + } + + return host_reg; +} + +static void OR_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*ORW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*ORB dst_reg, AL*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*ORB dst_reg, src_reg*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ORB dst_reg, src_reg*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void OR_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void OR_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*ORL dst_reg, src_reg*/ + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*ORL dst_reg, src_reg*/ + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void OR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ORW host_reg, imm<<8*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xc8 | (host_reg & 7)); + addword(imm << 8); + } + else if (host_reg & 8) + { + addbyte(0x41); /*ORL host_reg, imm*/ + addbyte(0x81); + addbyte(0xc8 | (host_reg & 7)); + addlong(imm); + } + else + fatal("OR to bad register\n"); +} + +static void XOR_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*XORW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*XORB dst_reg, AL*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*XORB dst_reg, src_reg*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*XORB dst_reg, src_reg*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void XOR_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void XOR_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*XORL dst_reg, src_reg*/ + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*XORL dst_reg, src_reg*/ + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ORW host_reg, imm<<8*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xf0 | (host_reg & 7)); + addword(imm << 8); + } + else if (host_reg & 8) + { + addbyte(0x41); /*ORL host_reg, imm*/ + addbyte(0x81); + addbyte(0xf0 | (host_reg & 7)); + addlong(imm); + } + else + fatal("XOR to bad register\n"); +} + +static void ADD_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*ADDW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*ADDB dst_reg, AL*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*ADDB dst_reg, src_reg*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ADDB dst_reg, src_reg*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void ADD_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void ADD_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*ADDL dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*ADDL dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} + +static void SUB_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*SUBW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*SUBB dst_reg, AL*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*SUBB dst_reg, src_reg*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*SUBB dst_reg, src_reg*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x41); /*MOVZX EBX, src_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x28); /*SUBB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x44); /*SUBB dst_reg, src_reg*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x0f); /*MOVZX EBX, src_reg*/ + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x28); /*SUBB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x28); /*SUBB dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + +// fatal("!(dst_reg & src_reg & 8) subb %i %i\n", dst_reg, src_reg); +} +static void SUB_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x44); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static void SUB_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*SUBL dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*SUBL dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x44); /*SUBL dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x29); /*SUBL dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} + +static int CMP_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = (dst_reg & 0x10) | REG_EDX; + } + + SUB_HOST_REG_B(dst_reg, src_reg); + + return dst_reg & ~0x10; +} +static int CMP_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + SUB_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static int CMP_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + SUB_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} + +static void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xC0 | (host_reg & 7)); + addword(imm << 8); + } + else + { + addbyte(0x41); /*ADDB host_reg, imm*/ + addbyte(0x80); + addbyte(0xC0 | (host_reg & 7)); + addbyte(imm); + } +} +static void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xC0 | (host_reg & 7)); + addword(imm); +} +static void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + addbyte(0x41); /*ADDL host_reg, imm*/ + addbyte(0x81); + addbyte(0xC0 | (host_reg & 7)); + addlong(imm); +} + +static void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*SUBW host_reg, imm*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xE8 | (host_reg & 7)); + addword(imm << 8); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x80); /*SUBB host_reg, imm*/ + addbyte(0xE8 | (host_reg & 7)); + addbyte(imm); + } +} +static void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + addbyte(0x66); /*SUBW host_reg, imm*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xE8 | (host_reg & 7)); + addword(imm); +} +static void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); /*SUBL host_reg, imm*/ + addbyte(0xE8 | (host_reg & 7)); + addlong(imm); +} + +static int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); + + host_reg = (host_reg & 0x10) | REG_EDX; + } + + SUB_HOST_REG_IMM_B(host_reg, imm); + + return host_reg;// & ~0x10; +} +static int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); + + host_reg = REG_EDX; + } + + SUB_HOST_REG_IMM_W(host_reg, imm); + + return host_reg; +} +static int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); + + host_reg = REG_EDX; + } + + SUB_HOST_REG_IMM(host_reg, imm); + + return host_reg; +} + +static void LOAD_STACK_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[ESP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[ESP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} +static void LOAD_EBP_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[EBP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&EBP - (uint32_t)&EAX); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[EBP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&EBP - (uint32_t)&EAX); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} + +static void SP_MODIFY(int off) +{ + if (stack32) + { + if (off < 0x80) + { + addbyte(0x83); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + addbyte(off); + } + else + { + addbyte(0x81); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + addlong(off); + } + } + else + { + if (off < 0x80) + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x83); + addbyte(0x45); + addbyte((uint32_t)&SP - (uint32_t)&EAX); + addbyte(off); + } + else + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x81); + addbyte(0x45); + addbyte((uint32_t)&SP - (uint32_t)&EAX); + addword(off); + } + } +} + +static void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uintptr_t)&cpu_state.flags_res - (uintptr_t)&cpu_state); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC(ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(12+2+2+7+5+(timing_bt ? 8 : 0)); + else + addbyte(12+2+2); + CALL_FUNC(CF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(timing_bt ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC(NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC(VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(timing_bt ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uintptr_t)&cpu_state.flags_res - (uintptr_t)&cpu_state); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC(ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(12+2+3+12+2+3+2+2+7+5+(timing_bt ? 8 : 0)); + else + addbyte(12+2+3+12+2+3+2+2); + + CALL_FUNC(NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC(VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(timing_bt ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int LOAD_VAR_W(uintptr_t addr) +{ + int host_reg = REG_EBX; + + addbyte(0x0f); /*MOVZX host_reg,[reg]*/ + addbyte(0xb7); + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)addr); + + return host_reg; +} +static int LOAD_VAR_L(uintptr_t addr) +{ + int host_reg = REG_EBX; + + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)addr); + + return host_reg; +} + +static int COPY_REG(int src_reg) +{ + if (src_reg & 8) + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | REG_ECX | ((src_reg & 7) << 3)); + + return REG_ECX | (src_reg & 0x10); +} + +static int LOAD_HOST_REG(int host_reg) +{ + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | REG_ECX | ((host_reg & 7) << 3)); + + return REG_ECX | (host_reg & 0x10); +} + +static int ZERO_EXTEND_W_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static int ZERO_EXTEND_L_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static int ZERO_EXTEND_L_W(int reg) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX regl, regw*/ + addbyte(0xb7); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} + +static int SIGN_EXTEND_W_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVSX EAX, AH*/ + addbyte(0xbe); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static int SIGN_EXTEND_L_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVSX EAX, AH*/ + addbyte(0xbe); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static int SIGN_EXTEND_L_W(int reg) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVSX regl, regw*/ + addbyte(0xbf); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} + +static void SHL_B_IMM(int reg, int count) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EAX | ((reg & 7) << 3)); + addbyte(0xc0); /*SHL AH, count*/ + addbyte(0xe0 | REG_AH); + addbyte(count); + addbyte(0x41); /*MOV reg, EAX*/ + addbyte(0x89); + addbyte(0xc0 | (REG_EAX << 3) | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xc0); /*SHL reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x20); + addbyte(count); + } +} +static void SHL_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHL reg, count*/ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); + addbyte(0xc0 | (reg & 7) | 0x20); + addbyte(count); +} +static void SHL_L_IMM(int reg, int count) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); /*SHL reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x20); + addbyte(count); +} +static void SHR_B_IMM(int reg, int count) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EAX | ((reg & 7) << 3)); + addbyte(0xc0); /*SHR AH, count*/ + addbyte(0xe8 | REG_AH); + addbyte(count); + addbyte(0x41); /*MOV reg, EAX*/ + addbyte(0x89); + addbyte(0xc0 | (REG_EAX << 3) | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xc0); /*SHR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x28); + addbyte(count); + } +} +static void SHR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHR reg, count*/ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); + addbyte(0xc0 | (reg & 7) | 0x28); + addbyte(count); +} +static void SHR_L_IMM(int reg, int count) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); /*SHR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x28); + addbyte(count); +} +static void SAR_B_IMM(int reg, int count) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EAX | ((reg & 7) << 3)); + addbyte(0xc0); /*SAR AH, count*/ + addbyte(0xf8 | REG_AH); + addbyte(count); + addbyte(0x41); /*MOV reg, EAX*/ + addbyte(0x89); + addbyte(0xc0 | (REG_EAX << 3) | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xc0); /*SAR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x38); + addbyte(count); + } +} +static void SAR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SAR reg, count*/ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); + addbyte(0xc0 | (reg & 7) | 0x38); + addbyte(count); +} +static void SAR_L_IMM(int reg, int count) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); /*SAR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x38); + addbyte(count); +} + +static void NEG_HOST_REG_B(int reg) +{ + if (reg & 0x10) + { + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV BX, reg*/ + addbyte(0xc3 | ((reg & 7) << 3)); + addbyte(0xf6); /*NEG BH*/ + addbyte(0xdf); + if (reg & 8) + addbyte(0x41); + addbyte(0x89); /*MOV reg, BX*/ + addbyte(0xd8 | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xf6); + addbyte(0xd8 | (reg & 7)); + } +} +static void NEG_HOST_REG_W(int reg) +{ + addbyte(0x66); + if (reg & 8) + addbyte(0x41); + addbyte(0xf7); + addbyte(0xd8 | (reg & 7)); +} +static void NEG_HOST_REG_L(int reg) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xf7); + addbyte(0xd8 | (reg & 7)); +} + + +static void FP_ENTER() +{ + if (codegen_fpu_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(11+5+12+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&oldpc); + addlong(op_old_pc); + load_param_1_32(&codeblock[block_current], 7); + CALL_FUNC(x86_int); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + codegen_fpu_entered = 1; +} + +static void FP_FXCH(int reg) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + + addbyte(0x48); /*MOV RDX, [RSI + RBX*8]*/ + addbyte(0x8b); + addbyte(0x14); + addbyte(0xde); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + addbyte(0x48); /*MOV RCX, [RSI + RAX*8]*/ + addbyte(0x8b); + addbyte(0x0c); + addbyte(0xc6); + addbyte(0x48); /*MOV [RSI + RAX*8], RDX*/ + addbyte(0x89); + addbyte(0x14); + addbyte(0xc6); + addbyte(0x48); /*MOV [RSI + RBX*8], RCX*/ + addbyte(0x89); + addbyte(0x0c); + addbyte(0xde); + + addbyte(0x48); /*MOVL ESI, tag*/ + addbyte(0xbe); + addquad((uintptr_t)tag); + addbyte(0x8a); /*MOV CL, tag[EAX]*/ + addbyte(0x14); + addbyte(0x1e); + addbyte(0x8a); /*MOV DL, tag[EBX]*/ + addbyte(0x0c); + addbyte(0x06); + addbyte(0x88); /*MOV tag[EBX], CL*/ + addbyte(0x14); + addbyte(0x06); + addbyte(0x88); /*MOV tag[EAX], DL*/ + addbyte(0x0c); + addbyte(0x1e); + + addbyte(0x48); /*MOV RSI, ST_i64*/ + addbyte(0xbe); + addquad((uint64_t)ST_i64); + addbyte(0x48); /*MOV RDX, [RSI + RBX*8]*/ + addbyte(0x8b); + addbyte(0x14); + addbyte(0xde); + addbyte(0x48); /*MOV RCX, [RSI + RAX*8]*/ + addbyte(0x8b); + addbyte(0x0c); + addbyte(0xc6); + addbyte(0x48); /*MOV [RSI + RAX*8], RDX*/ + addbyte(0x89); + addbyte(0x14); + addbyte(0xc6); + addbyte(0x48); /*MOV [RSI + RBX*8], RCX*/ + addbyte(0x89); + addbyte(0x0c); + addbyte(0xde); + reg = reg; +} + + + +static void FP_FLD(int reg) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + else + { + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + } + + addbyte(0x48); /*MOV RCX, ST[EAX*8]*/ + addbyte(0x8b); + addbyte(0x0c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(0x07); + addbyte(0x48); /*MOV RDX, ST_i64[EAX*8]*/ + addbyte(0x8b); + addbyte(0x14); + addbyte(0xc5); + addlong((uintptr_t)ST_i64); + addbyte(0x8a); /*MOV AL, [tag+EAX]*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(0x48); /*MOV ST[EBX*8], RCX*/ + addbyte(0x89); + addbyte(0x0c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x48); /*MOV ST_i64[EBX*8], RDX*/ + addbyte(0x89); + addbyte(0x14); + addbyte(0xdd); + addlong((uintptr_t)ST_i64); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x83); + addlong((uintptr_t)tag); + + addbyte(0x89); /*MOV [TOP], EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); +} + +static void FP_FST(int reg) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RCX, ST[EAX*8]*/ + addbyte(0x8b); + addbyte(0x0c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [tag+EAX]*/ + addbyte(0x98); + addlong((uintptr_t)tag); + + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + + addbyte(0x48); /*MOV ST[EAX*8], RCX*/ + addbyte(0x89); + addbyte(0x0c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x88); /*MOV [tag+EAX], BL*/ + addbyte(0x98); + addlong((uintptr_t)tag); +} + +static void FP_POP() +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0xc6); /*MOVB tag[EAX], 3*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(3); + addbyte(0x83); /*ADD AL, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x83); /*AND AL, 7*/ + addbyte(0xe0); + addbyte(7); + addbyte(0x89); /*MOV [TOP], EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); +} + +static void FP_LOAD_S() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf3); /*CVTSS2SD XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_D() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x48); /*TEST RAX, RAX*/ + addbyte(0x85); + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOVQ [ST+EBX*8], RAX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} + +static void FP_LOAD_IW() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x0f); /*MOVSX EAX, AX*/ + addbyte(0xbf); + addbyte(0xc0); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf2); /*CVTSI2SD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IL() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf2); /*CVTSI2SD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IQ() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf2); /*CVTSI2SDQ XMM0, RAX*/ + addbyte(0x48); + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x48); /*TEST RAX, RAX*/ + addbyte(0x85); + addbyte(0xc0); + addbyte(0x48); /*MOV [ST_i64+EBX*8], RAX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST_i64); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x0f); /*SETE AL*/ + addbyte(0x94); + addbyte(0xc0); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0c); /*OR AL, TAG_UINT64*/ + addbyte(TAG_UINT64); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x83); + addlong((uintptr_t)tag); +} + +static int FP_LOAD_REG(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc0 | REG_EBX); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe0 | REG_EBX); + addbyte(0x07); + } + addbyte(0xf3); /*MOVQ XMM0, ST[EBX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0xf2); /*CVTSD2SS XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc0); + addbyte(0x66); /*MOVD EBX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0 | REG_EBX); + + return REG_EBX; +} +static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc0 | REG_EBX); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe0 | REG_EBX); + addbyte(0x07); + } + addbyte(0x48); /*MOV RBX, ST[EBX*8]*/ + addbyte(0x8b); + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + + *host_reg1 = REG_EBX; +} +static int64_t x87_fround(double b) +{ + int64_t a, c; + + switch ((npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } +} +static int FP_LOAD_REG_INT_W(int reg) +{ + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + + CALL_FUNC(x87_fround); + + addbyte(0x93); /*XCHG EBX, EAX*/ + + return REG_EBX; +} +static int FP_LOAD_REG_INT(int reg) +{ + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + + CALL_FUNC(x87_fround); + + addbyte(0x93); /*XCHG EBX, EAX*/ + + return REG_EBX; +} +static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + if (codegen_fpu_loaded_iq[TOP] && (tag[TOP] & TAG_UINT64)) + { + /*If we know the register was loaded with FILDq in this block and + has not been modified, then we can skip most of the conversion + and just load the 64-bit integer representation directly */ + addbyte(0x48); /*MOV RAX, [ST_i64+EAX*8]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0xc5); + addlong((uint32_t)ST_i64); + + addbyte(0x48); /*XCHG RBX, RAX*/ + addbyte(0x93); + + *host_reg1 = REG_EBX; + + return; + } + + addbyte(0xf6); /*TEST TAG[EBX], TAG_UINT64*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(TAG_UINT64); + + addbyte(0x74); /*JZ +*/ + addbyte(8+2); + + addbyte(0x48); /*MOV RAX, [ST_i64+EAX*8]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0xc5); + addlong((uint32_t)ST_i64); + + addbyte(0xeb); /*JMP done*/ + addbyte(9+12); + + addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + + CALL_FUNC(x87_fround); + + addbyte(0x48); /*XCHG RBX, RAX*/ + addbyte(0x93); + + *host_reg1 = REG_EBX; +} + +#define FPU_ADD 0 +#define FPU_DIV 4 +#define FPU_DIVR 5 +#define FPU_MUL 1 +#define FPU_SUB 2 +#define FPU_SUBR 3 + +static void FP_OP_REG(int op, int dst, int src) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (dst) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + if (src) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc0 | REG_EBX); + addbyte(src); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe0 | REG_EBX); + addbyte(0x07); + } + if (op == FPU_DIVR || op == FPU_SUBR) + { + addbyte(0xf3); /*MOVQ XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xde); + } + else + { + addbyte(0xf3); /*MOVQ XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc6); + } + switch (op) + { + case FPU_ADD: + addbyte(0xf2); /*ADDSD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x58); + addbyte(0x04); + addbyte(0xde); + break; + case FPU_DIV: + addbyte(0xf2); /*DIVSD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0x04); + addbyte(0xde); + break; + case FPU_DIVR: + addbyte(0xf2); /*DIVSD XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0x04); + addbyte(0xc6); + break; + case FPU_MUL: + addbyte(0xf2); /*MULSD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x59); + addbyte(0x04); + addbyte(0xde); + break; + case FPU_SUB: + addbyte(0xf2); /*SUBSD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0x04); + addbyte(0xde); + break; + case FPU_SUBR: + addbyte(0xf2); /*SUBSD XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0x04); + addbyte(0xc6); + break; + } + addbyte(0x66); /*MOVQ [RSI+RAX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xc6); +} + +static void FP_OP_MEM(int op) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + addbyte(0xf3); /*MOVQ XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc6); + addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ + addbyte(0xa0 | REG_EAX); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + + switch (op) + { + case FPU_ADD: + addbyte(0xf2); /*ADDSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x58); + addbyte(0xc1); + break; + case FPU_DIV: + addbyte(0xf2); /*DIVSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0xc1); + break; + case FPU_DIVR: + addbyte(0xf2); /*DIVSD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0xc8); + break; + case FPU_MUL: + addbyte(0xf2); /*MULSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x59); + addbyte(0xc1); + break; + case FPU_SUB: + addbyte(0xf2); /*SUBSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0xc1); + break; + case FPU_SUBR: + addbyte(0xf2); /*SUBSD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0xc8); + break; + } + if (op == FPU_DIVR || op == FPU_SUBR) + { + addbyte(0x66); /*MOVQ [RSI+RAX*8], XMM1*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x0c); + addbyte(0xc6); + } + else + { + addbyte(0x66); /*MOVQ [RSI+RAX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xc6); + } +} + +static void FP_OP_S(int op) +{ + addbyte(0x66); /*MOVD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + addbyte(0xf3); /*CVTSS2SD XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc9); + FP_OP_MEM(op); +} +static void FP_OP_D(int op) +{ + addbyte(0x66); /*MOVQ XMM1, RAX*/ + addbyte(0x48); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x0f); /*STMXCSR [ESP+8]*/ + addbyte(0xae); + addbyte(0x5c); + addbyte(0x24); + addbyte(0x08); + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + addbyte(0x25); /*AND EAX, ~(3 << 13)*/ + addlong(~(3 << 10)); + addbyte(0x0d); /*OR EAX, (npxc & (3 << 10)) << 3*/ + addlong((npxc & (3 << 10)) << 3); + addbyte(0x89); /*MOV [RSP+12], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x0c); + addbyte(0x0f); /*LDMXCSR [RSP+12]*/ + addbyte(0xae); + addbyte(0x54); + addbyte(0x24); + addbyte(0x0c); + } + FP_OP_MEM(op); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x0f); /*LDMXCSR [RSP+8]*/ + addbyte(0xae); + addbyte(0x54); + addbyte(0x24); + addbyte(0x08); + } +} +static void FP_OP_IW(int op) +{ + addbyte(0x0f); /*MOVSX EAX, AX*/ + addbyte(0xbf); + addbyte(0xc0); + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_OP_MEM(op); +} +static void FP_OP_IL(int op) +{ + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_OP_MEM(op); +} + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +static void FP_COMPARE_REG(int dst, int src) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (src || dst) + { + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(src ? src : dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x0c); + addbyte(0x25); + addlong(((uintptr_t)&npxs) + 1); +// addbyte(0xdb); /*FCLEX*/ +// addbyte(0xe2); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + + if (src) + { + addbyte(0xf3); /*MOVQ XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xde); + addbyte(0x66); /*COMISD XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x2f); + addbyte(0x04); + addbyte(0xc6); + } + else + { + addbyte(0xf3); /*MOVQ XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc6); + addbyte(0x66); /*COMISD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x2f); + addbyte(0x04); + addbyte(0xde); + } + + addbyte(0x9f); /*LAHF*/ + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x0c); + addbyte(0x25); + addlong(((uintptr_t)&npxs) + 1); +} + +static void FP_COMPARE_MEM() +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x0c); + addbyte(0x25); + addlong(((uintptr_t)&npxs) + 1); +// addbyte(0xdb); /*FCLEX*/ +// addbyte(0xe2); + addbyte(0xf3); /*MOVQ XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc6); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0x66); /*COMISD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x2f); + addbyte(0xc1); + addbyte(0x9f); /*LAHF*/ + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x0c); + addbyte(0x25); + addlong(((uintptr_t)&npxs) + 1); +} +static void FP_COMPARE_S() +{ + addbyte(0x66); /*MOVD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + addbyte(0xf3); /*CVTSS2SD XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc9); + FP_COMPARE_MEM(); +} +static void FP_COMPARE_D() +{ + addbyte(0x66); /*MOVQ XMM1, RAX*/ + addbyte(0x48); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + FP_COMPARE_MEM(); +} +static void FP_COMPARE_IW() +{ + addbyte(0x0f); /*MOVSX EAX, AX*/ + addbyte(0xbf); + addbyte(0xc0); + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_COMPARE_MEM(); +} +static void FP_COMPARE_IL() +{ + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_COMPARE_MEM(); +} + +static void SET_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x0c); + addbyte(0x25); + addlong(addr); + addlong(val); + } + else + { + addbyte(0x80); + addbyte(0x0c); + addbyte(0x25); + addlong(addr); + addbyte(val); + } +} +static void CLEAR_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x24); + addbyte(0x25); + addlong(addr); + addlong(~val); + } + else + { + addbyte(0x80); + addbyte(0x24); + addbyte(0x25); + addlong(addr); + addbyte(~val); + } +} + +#define LOAD_Q_REG_1 REG_EAX +#define LOAD_Q_REG_2 REG_EDX + +static void MMX_ENTER() +{ + if (codegen_mmx_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(11+5+12+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&oldpc); + addlong(op_old_pc); + load_param_1_32(&codeblock[block_current], 7); + CALL_FUNC(x86_int); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xc7); /*MOV ISMMX, 1*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&ismmx); + addlong(1); + addbyte(0x89); /*MOV TOP, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&TOP); + addbyte(0x89); /*MOV tag, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&tag[0]); + addbyte(0x89); /*MOV tag+4, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&tag[4]); + + codegen_mmx_entered = 1; +} + +extern int mmx_ebx_ecx_loaded; + +static int LOAD_MMX_D(int guest_reg) +{ + int host_reg = REG_EBX; + + addbyte(0x8b); /*MOV EBX, reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].l[0]); + + return host_reg; +} +static void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) +{ + int host_reg = REG_EBX; + + if (host_reg & 8) + addbyte(0x4c); + else + addbyte(0x48); + addbyte(0x8b); /*MOV RBX, reg*/ + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].q); + + *host_reg1 = host_reg; +} +static int LOAD_MMX_Q_MMX(int guest_reg) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = 100; + + addbyte(0xf3); /*MOV XMMx, reg*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04 | ((dst_reg & 7) << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].q); + + return dst_reg; +} + +static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = 100; + + addbyte(0x66); /*MOVQ host_reg, src_reg1*/ + if (src_reg1 & 8) + addbyte(0x49); + else + addbyte(0x48); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0 | (dst_reg << 3) | (src_reg1 & 7)); + + return dst_reg; +} + +static void STORE_MMX_LQ(int guest_reg, int host_reg1) +{ + addbyte(0xC7); /*MOVL [reg],0*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].l[1]); + addlong(0); + if (host_reg1 & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x04 | ((host_reg1 & 7) << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].l[0]); +} +static void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) +{ + if (host_reg1 & 8) + addbyte(0x4c); + else + addbyte(0x48); + addbyte(0x89); /*MOV [reg],host_reg*/ + addbyte(0x04 | ((host_reg1 & 7) << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].l[0]); +} +static void STORE_MMX_Q_MMX(int guest_reg, int host_reg) +{ + addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].q); +} + +#define MMX_x86_OP(name, opcode) \ +static void MMX_ ## name(int dst_reg, int src_reg) \ +{ \ + addbyte(0x66); /*op dst_reg, src_reg*/ \ + addbyte(0x0f); \ + addbyte(opcode); \ + addbyte(0xc0 | (dst_reg << 3) | src_reg); \ +} + +MMX_x86_OP(AND, 0xdb) +MMX_x86_OP(ANDN, 0xdf) +MMX_x86_OP(OR, 0xeb) +MMX_x86_OP(XOR, 0xef) + +MMX_x86_OP(ADDB, 0xfc) +MMX_x86_OP(ADDW, 0xfd) +MMX_x86_OP(ADDD, 0xfe) +MMX_x86_OP(ADDSB, 0xec) +MMX_x86_OP(ADDSW, 0xed) +MMX_x86_OP(ADDUSB, 0xdc) +MMX_x86_OP(ADDUSW, 0xdd) + +MMX_x86_OP(SUBB, 0xf8) +MMX_x86_OP(SUBW, 0xf9) +MMX_x86_OP(SUBD, 0xfa) +MMX_x86_OP(SUBSB, 0xe8) +MMX_x86_OP(SUBSW, 0xe9) +MMX_x86_OP(SUBUSB, 0xd8) +MMX_x86_OP(SUBUSW, 0xd9) + +MMX_x86_OP(PUNPCKLBW, 0x60); +MMX_x86_OP(PUNPCKLWD, 0x61); +MMX_x86_OP(PUNPCKLDQ, 0x62); +MMX_x86_OP(PCMPGTB, 0x64); +MMX_x86_OP(PCMPGTW, 0x65); +MMX_x86_OP(PCMPGTD, 0x66); + +MMX_x86_OP(PCMPEQB, 0x74); +MMX_x86_OP(PCMPEQW, 0x75); +MMX_x86_OP(PCMPEQD, 0x76); + +MMX_x86_OP(PSRLW, 0xd1); +MMX_x86_OP(PSRLD, 0xd2); +MMX_x86_OP(PSRLQ, 0xd3); +MMX_x86_OP(PSRAW, 0xe1); +MMX_x86_OP(PSRAD, 0xe2); +MMX_x86_OP(PSLLW, 0xf1); +MMX_x86_OP(PSLLD, 0xf2); +MMX_x86_OP(PSLLQ, 0xf3); + +MMX_x86_OP(PMULLW, 0xd5); +MMX_x86_OP(PMULHW, 0xe5); +MMX_x86_OP(PMADDWD, 0xf5); + +static void MMX_PACKSSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x63); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PACKUSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PACKSSDW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PUNPCKHBW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static void MMX_PUNPCKHWD(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static void MMX_PUNPCKHDQ(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} + +static void MMX_PSRLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static void MMX_PSRLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static void MMX_PSRLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} diff --git a/src/codegen_ops_x86.h b/src/codegen_ops_x86.h new file mode 100644 index 000000000..3e077f24a --- /dev/null +++ b/src/codegen_ops_x86.h @@ -0,0 +1,3393 @@ +/*Register allocation : + EBX, ECX, EDX - emulated registers + EAX - work register, EA storage + ESI, EDI - work registers + EBP - points at emulated register array +*/ +#define HOST_REG_START 1 +#define HOST_REG_END 4 +#define HOST_REG_XMM_START 0 +#define HOST_REG_XMM_END 7 +static inline int find_host_reg() +{ + int c; + for (c = HOST_REG_START; c < HOST_REG_END; c++) + { + if (host_reg_mapping[c] == -1) + break; + } + + if (c == NR_HOST_REGS) + fatal("Out of host regs!\n"); + return c; +} +static inline int find_host_xmm_reg() +{ + int c; + for (c = HOST_REG_XMM_START; c < HOST_REG_XMM_END; c++) + { + if (host_reg_xmm_mapping[c] == -1) + break; + } + + if (c == HOST_REG_XMM_END) + fatal("Out of host XMM regs!\n"); + return c; +} + +static void STORE_IMM_ADDR_B(uintptr_t addr, uint8_t val) +{ + addbyte(0xC6); /*MOVB [addr],val*/ + addbyte(0x05); + addlong(addr); + addbyte(val); +} +static void STORE_IMM_ADDR_W(uintptr_t addr, uint16_t val) +{ + addbyte(0x66); /*MOVW [addr],val*/ + addbyte(0xC7); + addbyte(0x05); + addlong(addr); + addword(val); +} +static void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x45); + addbyte(addr - (uint32_t)&cpu_state); + addlong(val); + } + else + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x05); + addlong(addr); + addlong(val); + } +} + +static void STORE_IMM_REG_B(int reg, uint8_t val) +{ + addbyte(0xC6); /*MOVB [addr],val*/ + addbyte(0x45); + if (reg & 4) + addbyte((uint32_t)&cpu_state.regs[reg & 3].b.h - (uint32_t)&EAX); + else + addbyte((uint32_t)&cpu_state.regs[reg & 3].b.l - (uint32_t)&EAX); + addbyte(val); +} +static void STORE_IMM_REG_W(int reg, uint16_t val) +{ + addbyte(0x66); /*MOVW [addr],val*/ + addbyte(0xC7); + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[reg & 7].w - (uint32_t)&EAX); + addword(val); +} +static void STORE_IMM_REG_L(int reg, uint32_t val) +{ + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[reg & 7].l - (uint32_t)&EAX); + addlong(val); +} + +static int LOAD_REG_B(int reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x0f); /*MOVZX B[reg],host_reg*/ + addbyte(0xb6); + addbyte(0x45 | (host_reg << 3)); + if (reg & 4) + addbyte((uint32_t)&cpu_state.regs[reg & 3].b.h - (uint32_t)&EAX); + else + addbyte((uint32_t)&cpu_state.regs[reg & 3].b.l - (uint32_t)&EAX); + + return host_reg; +} +static int LOAD_REG_W(int reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x0f); /*MOVZX W[reg],host_reg*/ + addbyte(0xb7); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].w - (uint32_t)&EAX); + + return host_reg; +} +static int LOAD_REG_L(int reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].l - (uint32_t)&EAX); + + return host_reg; +} + +static int LOAD_VAR_W(uintptr_t addr) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x66); /*MOVL host_reg,[reg]*/ + addbyte(0x8b); + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)addr); + + return host_reg; +} +static int LOAD_VAR_L(uintptr_t addr) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)addr); + + return host_reg; +} + +static int LOAD_REG_IMM(uint32_t imm) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0xc7); /*MOVL host_reg, imm*/ + addbyte(0xc0 | host_reg); + addlong(imm); + + return host_reg; +} + +static int LOAD_HOST_REG(int host_reg) +{ + int new_host_reg = find_host_reg(); + host_reg_mapping[new_host_reg] = reg; + + addbyte(0x89); /*MOV new_host_reg, host_reg*/ + addbyte(0xc0 | (host_reg << 3) | new_host_reg); + + return new_host_reg; +} + +static void STORE_REG_B_RELEASE(int host_reg) +{ + addbyte(0x88); /*MOVB [reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + if (host_reg_mapping[host_reg] & 4) + addbyte((uint32_t)&cpu_state.regs[host_reg_mapping[host_reg] & 3].b.h - (uint32_t)&EAX); + else + addbyte((uint32_t)&cpu_state.regs[host_reg_mapping[host_reg] & 3].b.l - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} +static void STORE_REG_W_RELEASE(int host_reg) +{ + addbyte(0x66); /*MOVW [reg],host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg_mapping[host_reg]].w - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} +static void STORE_REG_L_RELEASE(int host_reg) +{ + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg_mapping[host_reg]].l - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} + +static void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) +{ + addbyte(0x88); /*MOVB [guest_reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + if (guest_reg & 4) + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b.h - (uint32_t)&EAX); + else + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b.l - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} +static void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) +{ + addbyte(0x66); /*MOVW [guest_reg],host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].w - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} +static void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) +{ + addbyte(0x89); /*MOVL [guest_reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].l - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} + +static void RELEASE_REG(int host_reg) +{ + host_reg_mapping[host_reg] = -1; +} + +static void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0x66); /*MOVW [addr],host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + addbyte(0x66); /*MOVL [reg],host_reg*/ + addbyte(0x89); + addbyte(0x05 | (host_reg << 3)); + addlong(addr); + } +} +static void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0x89); /*MOVL [addr],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x05 | (host_reg << 3)); + addlong(addr); + } +} +#define STORE_HOST_REG_ADDR_BL STORE_HOST_REG_ADDR +#define STORE_HOST_REG_ADDR_WL STORE_HOST_REG_ADDR + +static void ADD_HOST_REG_B(int dst_reg, int src_reg) +{ + addbyte(0x00); /*ADDB dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void ADD_HOST_REG_W(int dst_reg, int src_reg) +{ + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void ADD_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x01); /*ADDL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + addbyte(0x80); /*ADDB host_reg, imm*/ + addbyte(0xC0 | host_reg); + addbyte(imm); +} +static void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + if (imm < 0x80 || imm >= 0xff80) + { + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x83); + addbyte(0xC0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x81); + addbyte(0xC0 | host_reg); + addword(imm); + } +} +static void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*ADDL host_reg, imm*/ + addbyte(0xC0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*ADDL host_reg, imm*/ + addbyte(0xC0 | host_reg); + addlong(imm); + } +} + +#define AND_HOST_REG_B AND_HOST_REG_L +#define AND_HOST_REG_W AND_HOST_REG_L +static void AND_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x21); /*ANDL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void AND_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*ANDL host_reg, imm*/ + addbyte(0xE0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*ANDL host_reg, imm*/ + addbyte(0xE0 | host_reg); + addlong(imm); + } +} +static int TEST_HOST_REG_B(int dst_reg, int src_reg) +{ + AND_HOST_REG_B(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_W(int dst_reg, int src_reg) +{ + AND_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_L(int dst_reg, int src_reg) +{ + AND_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + AND_HOST_REG_IMM(host_reg, imm); + + return host_reg; +} + +#define OR_HOST_REG_B OR_HOST_REG_L +#define OR_HOST_REG_W OR_HOST_REG_L +static void OR_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x09); /*ORL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void OR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*ORL host_reg, imm*/ + addbyte(0xC8 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*ORL host_reg, imm*/ + addbyte(0xC8 | host_reg); + addlong(imm); + } +} + +static void NEG_HOST_REG_B(int reg) +{ + addbyte(0xf6); + addbyte(0xd8 | reg); +} +static void NEG_HOST_REG_W(int reg) +{ + addbyte(0x66); + addbyte(0xf7); + addbyte(0xd8 | reg); +} +static void NEG_HOST_REG_L(int reg) +{ + addbyte(0xf7); + addbyte(0xd8 | reg); +} + +static void SUB_HOST_REG_B(int dst_reg, int src_reg) +{ + addbyte(0x28); /*SUBB dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void SUB_HOST_REG_W(int dst_reg, int src_reg) +{ + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void SUB_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x29); /*SUBL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + addbyte(0x80); /*SUBB host_reg, imm*/ + addbyte(0xE8 | host_reg); + addbyte(imm); +} +static void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + if (imm < 0x80 || imm >= 0xff80) + { + addbyte(0x66); /*SUBW host_reg, imm*/ + addbyte(0x83); + addbyte(0xE8 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x66); /*SUBW host_reg, imm*/ + addbyte(0x81); + addbyte(0xE8 | host_reg); + addword(imm); + } +} +static void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*SUBL host_reg, imm*/ + addbyte(0xE8 | host_reg); + addbyte(imm); + } + else + { + addbyte(0x81); /*SUBL host_reg, imm*/ + addbyte(0xE8 | host_reg); + addlong(imm); + } +} + +static int CMP_HOST_REG_B(int dst_reg, int src_reg) +{ + SUB_HOST_REG_B(dst_reg, src_reg); + + return dst_reg; +} +static int CMP_HOST_REG_W(int dst_reg, int src_reg) +{ + SUB_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static int CMP_HOST_REG_L(int dst_reg, int src_reg) +{ + SUB_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} +static int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + SUB_HOST_REG_IMM_B(host_reg, imm); + + return host_reg; +} +static int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + SUB_HOST_REG_IMM_W(host_reg, imm); + + return host_reg; +} +static int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) +{ + SUB_HOST_REG_IMM(host_reg, imm); + + return host_reg; +} + +#define XOR_HOST_REG_B XOR_HOST_REG_L +#define XOR_HOST_REG_W XOR_HOST_REG_L +static void XOR_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x31); /*XORL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*XORL host_reg, imm*/ + addbyte(0xF0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*XORL host_reg, imm*/ + addbyte(0xF0 | host_reg); + addlong(imm); + } +} + +static void CALL_FUNC(void *dest) +{ + addbyte(0xE8); /*CALL*/ + addlong(((uint8_t *)dest - (uint8_t *)(&codeblock[block_current].data[block_pos + 4]))); +} + +static void SHL_B_IMM(int reg, int count) +{ + addbyte(0xc0); /*SHL reg, count*/ + addbyte(0xc0 | reg | 0x20); + addbyte(count); +} +static void SHL_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHL reg, count*/ + addbyte(0xc1); + addbyte(0xc0 | reg | 0x20); + addbyte(count); +} +static void SHL_L_IMM(int reg, int count) +{ + addbyte(0xc1); /*SHL reg, count*/ + addbyte(0xc0 | reg | 0x20); + addbyte(count); +} +static void SHR_B_IMM(int reg, int count) +{ + addbyte(0xc0); /*SHR reg, count*/ + addbyte(0xc0 | reg | 0x28); + addbyte(count); +} +static void SHR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHR reg, count*/ + addbyte(0xc1); + addbyte(0xc0 | reg | 0x28); + addbyte(count); +} +static void SHR_L_IMM(int reg, int count) +{ + addbyte(0xc1); /*SHR reg, count*/ + addbyte(0xc0 | reg | 0x28); + addbyte(count); +} +static void SAR_B_IMM(int reg, int count) +{ + addbyte(0xc0); /*SAR reg, count*/ + addbyte(0xc0 | reg | 0x38); + addbyte(count); +} +static void SAR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SAR reg, count*/ + addbyte(0xc1); + addbyte(0xc0 | reg | 0x38); + addbyte(count); +} +static void SAR_L_IMM(int reg, int count) +{ + addbyte(0xc1); /*SAR reg, count*/ + addbyte(0xc0 | reg | 0x38); + addbyte(count); +} + + +static void CHECK_SEG_READ(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x05|0x38); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); + addbyte(0x84); /*JE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static void CHECK_SEG_WRITE(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x05|0x38); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); + addbyte(0x84); /*JE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) +{ + addbyte(0x3b); /*CMP EAX, seg->limit_low*/ + addbyte(0x05); + addlong((uint32_t)&seg->limit_low); + addbyte(0x0f); /*JB BLOCK_GPF_OFFSET*/ + addbyte(0x82); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + if (end_offset) + { + addbyte(0x83); /*ADD EAX, end_offset*/ + addbyte(0xc0); + addbyte(end_offset); + addbyte(0x3b); /*CMP EAX, seg->limit_high*/ + addbyte(0x05); + addlong((uint32_t)&seg->limit_high); + addbyte(0x0f); /*JNBE BLOCK_GPF_OFFSET*/ + addbyte(0x87); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + addbyte(0x83); /*SUB EAX, end_offset*/ + addbyte(0xe8); + addbyte(end_offset); + } +} + +static void MEM_LOAD_ADDR_EA_B(x86seg *seg) +{ + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x0f); /*MOVZX EAX, B[EDX+EDI]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x3a); + addbyte(0xeb); /*JMP done*/ + addbyte(4+3+5+7+6+3); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0x89); /*MOV [ESP], ESI*/ + addbyte(0x34); + addbyte(0x24); + addbyte(0xe8); /*CALL readmemb386l*/ + addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + addbyte(0x0f); /*MOVZX EAX, AL*/ + addbyte(0xb6); + addbyte(0xc0); + /*done:*/ + host_reg_mapping[0] = 8; +} +static void MEM_LOAD_ADDR_EA_W(x86seg *seg) +{ + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x8d); /*LEA EDI, 1[EDX]*/ + addbyte(0x7a); + addbyte(0x01); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xc7); + addlong(0xfff); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + addbyte(0x0f); /*MOVZX EAX, -1[EDX+EDI]W*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x3a); + addbyte(-1); + addbyte(0xeb); /*JMP done*/ + addbyte(4+3+5+7+6+3); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0x89); /*MOV [ESP], ESI*/ + addbyte(0x34); + addbyte(0x24); + addbyte(0xe8); /*CALL readmemwl*/ + addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); + addbyte(0x85); /*JNE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + addbyte(0x0f); /*MOVZX EAX, AX*/ + addbyte(0xb7); + addbyte(0xc0); + /*done:*/ + host_reg_mapping[0] = 8; +} +static void MEM_LOAD_ADDR_EA_L(x86seg *seg) +{ + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x8d); /*LEA EDI, 3[EDX]*/ + addbyte(0x7a); + addbyte(0x03); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xc7); + addlong(0xffc); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x8b); /*MOV EAX, -3[EDX+EDI]*/ + addbyte(0x44); + addbyte(0x3a); + addbyte(-3); + addbyte(0xeb); /*JMP done*/ + addbyte(4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0x89); /*MOV [ESP], ESI*/ + addbyte(0x34); + addbyte(0x24); + addbyte(0xe8); /*CALL readmemll*/ + addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); + addbyte(0x85); /*JNE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ + host_reg_mapping[0] = 8; +} + +static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) +{ + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x8d); /*LEA EDI, 7[EDX]*/ + addbyte(0x7a); + addbyte(0x07); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xc7); + addlong(0xff8); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+4+2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+4+2); + addbyte(0x8b); /*MOV EAX, [EDX+EDI]*/ + addbyte(0x44); + addbyte(0x3a); + addbyte(-7); + addbyte(0x8b); /*MOV EDX, [EDX+EDI+4]*/ + addbyte(0x54); + addbyte(0x3a); + addbyte(-7+4); + addbyte(0xeb); /*JMP done*/ + addbyte(4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0x89); /*MOV [ESP], ESI*/ + addbyte(0x34); + addbyte(0x24); + addbyte(0xe8); /*CALL readmemql*/ + addlong((uint32_t)readmemql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); + addbyte(0x85); /*JNE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ + host_reg_mapping[0] = 8; +} + +static void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_B(seg); +} +static void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_W(seg); +} +static void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_L(seg); +} + +static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xc0 | (REG_ESI << 3) | REG_EDI); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2); + addbyte(0x88); /*MOV [EDI+ESI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(4+5+4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0xa1); /*MOV EAX, seg->base*/ + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV [ESP+8], host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xe8); /*CALL writememb386l*/ + addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x8d); /*LEA EDI, 1[ESI]*/ + addbyte(0x7e); + addbyte(0x01); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xc7); + addlong(0xfff); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + addbyte(0x66); /*MOV -1[EDI+ESI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-1); + addbyte(0xeb); /*JMP done*/ + addbyte(4+5+4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0xa1); /*MOV EAX, seg->base*/ + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV [ESP+8], host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xe8); /*CALL writememwl*/ + addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x8d); /*LEA EDI, 3[ESI]*/ + addbyte(0x7e); + addbyte(0x03); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xc7); + addlong(0xffc); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x89); /*MOV -3[EDI+ESI],host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-3); + addbyte(0xeb); /*JMP done*/ + addbyte(4+5+4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0xa1); /*MOV EAX, seg->base*/ + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV [ESP+8], host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xe8); /*CALL writememll*/ + addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +{ + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x8d); /*LEA EDI, 7[ESI]*/ + addbyte(0x7e); + addbyte(0x07); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xc7); + addlong(0xff8); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+4+2); + addbyte(0x89); /*MOV [EDI+ESI],host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7); + addbyte(0x89); /*MOV [EDI+ESI+4],host_reg2*/ + addbyte(0x44 | (host_reg2 << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7+0x04); + addbyte(0xeb); /*JMP done*/ + addbyte(4+5+4+4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0xa1); /*MOV EAX, seg->base*/ + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV [ESP+8], host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP+12], host_reg2*/ + addbyte(0x44 | (host_reg2 << 3)); + addbyte(0x24); + addbyte(0x0c); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xe8); /*CALL writememql*/ + addlong((uint32_t)writememql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} + +static void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_B(seg, host_reg); +} +static void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_L(seg, host_reg); +} +static void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_W(seg, host_reg); +} + + +static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + int mod = (fetchdat >> 6) & 3; + int reg = (fetchdat >> 3) & 7; + int rm = fetchdat & 7; + if (!mod && rm == 6) + { + addbyte(0xb8); /*MOVL EAX, imm16*/ + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + switch (mod) + { + case 0: + addbyte(0xa1); /*MOVL EAX, *mod1add[0][rm]*/ + addlong((uint32_t)mod1add[0][rm]); + if (mod1add[1][rm] != &zero) + { + addbyte(0x03); /*ADDL EAX, *mod1add[1][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + } + break; + case 1: + addbyte(0xa1); /*MOVL EAX, *mod1add[0][rm]*/ + addlong((uint32_t)mod1add[0][rm]); + addbyte(0x83); /*ADDL EAX, imm8*/ + addbyte(0xc0 | REG_EAX); + addbyte((int8_t)(rmdat >> 8)); + if (mod1add[1][rm] != &zero) + { + addbyte(0x03); /*ADDL EAX, *mod1add[1][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + } + (*op_pc)++; + break; + case 2: + addbyte(0xb8); /*MOVL EAX, imm16*/ + addlong((fetchdat >> 8) & 0xffff);// pc++; + addbyte(0x03); /*ADDL EAX, *mod1add[0][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[0][rm]); + if (mod1add[1][rm] != &zero) + { + addbyte(0x03); /*ADDL EAX, *mod1add[1][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + } + (*op_pc) += 2; + break; + } + addbyte(0x25); /*ANDL EAX, 0xffff*/ + addlong(0xffff); + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} + +static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + uint32_t new_eaaddr; + int mod = (fetchdat >> 6) & 3; + int reg = (fetchdat >> 3) & 7; + int rm = fetchdat & 7; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + (*op_pc)++; + + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, imm32*/ + addlong(new_eaaddr);// pc++; + (*op_pc) += 4; + } + else + { + addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[sib & 7].l - (uint32_t)&EAX); + } + break; + case 1: + addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[sib & 7].l - (uint32_t)&EAX); + addbyte(0x83); /*ADDL EAX, imm8*/ + addbyte(0xc0 | REG_EAX); + addbyte((int8_t)(rmdat >> 16)); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, new_eaaddr*/ + addlong(new_eaaddr); + addbyte(0x03); /*ADDL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[sib & 7].l - (uint32_t)&EAX); + (*op_pc) += 4; + break; + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + if (stack_offset < 0x80 || stack_offset >= 0xffffff80) + { + addbyte(0x83); + addbyte(0xc0 | REG_EAX); + addbyte(stack_offset); + } + else + { + addbyte(0x05); /*ADDL EAX, stack_offset*/ + addlong(stack_offset); + } + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + if (((sib >> 3) & 7) != 4) + { + switch (sib >> 6) + { + case 0: + addbyte(0x03); /*ADDL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[(sib >> 3) & 7].l - (uint32_t)&EAX); + break; + case 1: + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint32_t)&cpu_state.regs[(sib >> 3) & 7].l - (uint32_t)&EAX); /*MOVL EDI, reg*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + break; + case 2: + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint32_t)&cpu_state.regs[(sib >> 3) & 7].l - (uint32_t)&EAX); /*MOVL EDI, reg*/ + addbyte(0xC1); addbyte(0xE0 | REG_EDI); addbyte(2); /*SHL EDI, 2*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + break; + case 3: + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint32_t)&cpu_state.regs[(sib >> 3) & 7].l - (uint32_t)&EAX); /*MOVL EDI reg*/ + addbyte(0xC1); addbyte(0xE0 | REG_EDI); addbyte(3); /*SHL EDI, 3*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + break; + } + } + } + else + { + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + addbyte(0x8b); /*MOVL EAX, regs[rm].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[rm].l - (uint32_t)&EAX); + eaaddr = cpu_state.regs[rm].l; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x83); /*ADD EAX, imm8*/ + addbyte(0xc0 | REG_EAX); + addbyte((int8_t)(fetchdat >> 8)); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x05); /*ADD EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + } + } + return op_ea_seg; +} + +static x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) +{ + if (op_32 & 0x200) + return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); + return FETCH_EA_16(op_ea_seg, fetchdat, op_ssegs, op_pc); +} + + +static void LOAD_STACK_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[ESP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[ESP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} + +static void LOAD_EBP_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[EBP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&EBP - (uint32_t)&EAX); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[EBP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&EBP - (uint32_t)&EAX); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} + +static void SP_MODIFY(int off) +{ + if (stack32) + { + if (off < 0x80) + { + addbyte(0x83); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + addbyte(off); + } + else + { + addbyte(0x81); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + addlong(off); + } + } + else + { + if (off < 0x80) + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x83); + addbyte(0x45); + addbyte((uint32_t)&SP - (uint32_t)&EAX); + addbyte(off); + } + else + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x81); + addbyte(0x45); + addbyte((uint32_t)&SP - (uint32_t)&EAX); + addword(off); + } + } +} + + +static void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + addbyte(0x83); + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + addbyte(0x83); + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: + addbyte(0x8a); /*MOV AL, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3a); /*CMP AL, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x76); /*JBE*/ + else + addbyte(0x77); /*JNBE*/ + break; + case FLAGS_SUB16: + addbyte(0x66); /*MOV AX, flags_op1*/ + addbyte(0x8b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x66); /*CMP AX, flags_op2*/ + addbyte(0x3b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x76); /*JBE*/ + else + addbyte(0x77); /*JNBE*/ + break; + case FLAGS_SUB32: + addbyte(0x8b); /*MOV EAX, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3b); /*CMP EAX, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x76); /*JBE*/ + else + addbyte(0x77); /*JNBE*/ + break; + + default: + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uintptr_t)&cpu_state.flags_res - (uintptr_t)&cpu_state); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC(ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(5+2+2+7+5+(timing_bt ? 7 : 0)); + else + addbyte(5+2+2); + CALL_FUNC(CF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + break; + } + addbyte(7+5+(timing_bt ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: + addbyte(0x8a); /*MOV AL, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3a); /*CMP AL, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7c); /*JL*/ + else + addbyte(0x7d); /*JNL*/ + break; + case FLAGS_SUB16: + addbyte(0x66); /*MOV AX, flags_op1*/ + addbyte(0x8b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x66); /*CMP AX, flags_op2*/ + addbyte(0x3b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7c); /*JL*/ + else + addbyte(0x7d); /*JNL*/ + break; + case FLAGS_SUB32: + addbyte(0x8b); /*MOV EAX, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3b); /*CMP EAX, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7c); /*JL*/ + else + addbyte(0x7d); /*JNL*/ + break; + + default: + CALL_FUNC(NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC(VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + break; + } + addbyte(7+5+(timing_bt ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: + addbyte(0x8a); /*MOV AL, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3a); /*CMP AL, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7e); /*JLE*/ + else + addbyte(0x7f); /*JNLE*/ + break; + case FLAGS_SUB16: + addbyte(0x66); /*MOV AX, flags_op1*/ + addbyte(0x8b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x66); /*CMP AX, flags_op2*/ + addbyte(0x3b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7e); /*JLE*/ + else + addbyte(0x7f); /*JNLE*/ + break; + case FLAGS_SUB32: + addbyte(0x8b); /*MOV EAX, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3b); /*CMP EAX, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7e); /*JLE*/ + else + addbyte(0x7f); /*JNLE*/ + break; + + default: + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uintptr_t)&cpu_state.flags_res - (uintptr_t)&cpu_state); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC(ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(5+2+3+5+2+3+2+2+7+5+(timing_bt ? 7 : 0)); + else + addbyte(5+2+3+5+2+3+2+2); + + CALL_FUNC(NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC(VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + break; + } + addbyte(7+5+(timing_bt ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + + +static void FP_ENTER() +{ + if (codegen_fpu_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x05); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(10+7+5+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x05); + addlong((uintptr_t)&oldpc); + addlong(op_old_pc); + addbyte(0xc7); /*MOV [ESP], 7*/ + addbyte(0x04); + addbyte(0x24); + addlong(7); + addbyte(0xe8); /*CALL x86_int*/ + addlong((uint32_t)x86_int - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + codegen_fpu_entered = 1; +} + +static void FP_FLD(int reg) +{ + addbyte(0xa1); /*MOV EAX, [TOP]*/ + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + else + { + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + } + + addbyte(0xdd); /*FLD [ST+EAX*8]*/ + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(0x07); + addbyte(0x8b); /*MOV EDX, [ST_i64+EAX]*/ + addbyte(0x14); + addbyte(0xc5); + addlong((uintptr_t)ST_i64); + addbyte(0x8b); /*MOV ECX, [ST_i64+4+EAX]*/ + addbyte(0x0c); + addbyte(0xc5); + addlong(((uintptr_t)ST_i64) + 4); + addbyte(0x8a); /*MOV AL, [tag+EAX]*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x83); + addlong((uintptr_t)tag); + addbyte(0x89); /*MOV [ST_i64+EBX], EDX*/ + addbyte(0x14); + addbyte(0xdd); + addlong((uintptr_t)ST_i64); + addbyte(0x89); /*MOV [ST_i64+EBX+4], ECX*/ + addbyte(0x0c); + addbyte(0xdd); + addlong(((uintptr_t)ST_i64) + 4); + + addbyte(0x89); /*MOV [TOP], EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); +} + +static void FP_FST(int reg) +{ + addbyte(0xa1); /*MOV EAX, [TOP]*/ + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FLD [ST+EAX*8]*/ + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x88); /*MOV BL, [tag+EAX]*/ + addbyte(0x98); + addlong((uintptr_t)tag); + + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + + addbyte(0xdd); /*FSTP [ST+EAX*8]*/ + addbyte(0x1c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV [tag+EAX], BL*/ + addbyte(0x98); + addlong((uintptr_t)tag); +} + +static void FP_FXCH(int reg) +{ + addbyte(0xa1); /*MOV EAX, [TOP]*/ + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); +//#if 0 + addbyte(0xdd); /*FLD [ST+EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + addbyte(0xdd); /*FLD [ST+EAX*8]*/ + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0xdd); /*FSTP [ST+EAX*8]*/ + addbyte(0x1c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0xbe); /*MOVL ESI, tag*/ + addlong((uintptr_t)tag); + addbyte(0x8a); /*MOV CL, tag[EAX]*/ + addbyte(0x0c); + addbyte(0x06); + addbyte(0x8a); /*MOV DL, tag[EBX]*/ + addbyte(0x14); + addbyte(0x1e); + addbyte(0x88); /*MOV tag[EBX], CL*/ + addbyte(0x0c); + addbyte(0x1e); + addbyte(0x88); /*MOV tag[EAX], DL*/ + addbyte(0x14); + addbyte(0x06); + addbyte(0xbe); /*MOVL ESI, ST_int64*/ + addlong((uintptr_t)ST_i64); + addbyte(0x8b); /*MOV ECX, ST_int64[EAX*8]*/ + addbyte(0x0c); + addbyte(0xc6); + addbyte(0x8b); /*MOV EDX, ST_int64[EBX*8]*/ + addbyte(0x14); + addbyte(0xde); + addbyte(0x89); /*MOV ST_int64[EBX*8], ECX*/ + addbyte(0x0c); + addbyte(0xde); + addbyte(0x89); /*MOV ST_int64[EAX*8], EDX*/ + addbyte(0x14); + addbyte(0xc6); + addbyte(0x8b); /*MOV ECX, ST_int64[EAX*8]+4*/ + addbyte(0x4c); + addbyte(0xc6); + addbyte(0x04); + addbyte(0x8b); /*MOV EDX, ST_int64[EBX*8]+4*/ + addbyte(0x54); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOV ST_int64[EBX*8]+4, ECX*/ + addbyte(0x4c); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOV ST_int64[EAX*8]+4, EDX*/ + addbyte(0x54); + addbyte(0xc6); + addbyte(0x04); + reg = reg; +//#endif +#if 0 + addbyte(0xbe); /*MOVL ESI, ST*/ + addlong((uintptr_t)ST); + + addbyte(0x8b); /*MOVL EDX, [ESI+EBX*8]*/ + addbyte(0x14); + addbyte(0xde); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + addbyte(0x8b); /*MOVL ECX, [ESI+EAX*8]*/ + addbyte(0x0c); + addbyte(0xc6); + addbyte(0x89); /*MOVL [ESI+EBX*8], ECX*/ + addbyte(0x0c); + addbyte(0xde); + addbyte(0x89); /*MOVL [ESI+EAX*8], EDX*/ + addbyte(0x14); + addbyte(0xc6); + + addbyte(0x8b); /*MOVL ECX, [4+ESI+EAX*8]*/ + addbyte(0x4c); + addbyte(0xc6); + addbyte(0x04); + addbyte(0x8b); /*MOVL EDX, [4+ESI+EBX*8]*/ + addbyte(0x54); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOVL [4+ESI+EBX*8], ECX*/ + addbyte(0x4c); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOVL [4+ESI+EAX*8], EDX*/ + addbyte(0x54); + addbyte(0xc6); + addbyte(0x04); +#endif +} + + +static void FP_LOAD_S() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0xd9); /*FLD [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_D() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0xdd); /*FLD [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IW() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0xdf); /*FILDw [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IL() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0xdb); /*FILDl [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IQ() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x89); /*MOV [ST_i64+EBX*8], EAX*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uint32_t)ST_i64); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0x89); /*MOV [ST_i64+4+EBX*8], EDX*/ + addbyte(0x14); + addbyte(0xdd); + addlong(((uint32_t)ST_i64) + 4); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0xdf); /*FILDl [ST_i64+EBX*8]*/ + addbyte(0x2c); + addbyte(0xdd); + addlong((uint32_t)ST_i64); + addbyte(0x0f); /*SETE AL*/ + addbyte(0x94); + addbyte(0xc0); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0c); /*OR AL, TAG_UINT64*/ + addbyte(TAG_UINT64); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x83); + addlong((uint32_t)tag); +} + +static int FP_LOAD_REG(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0xd9); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + addbyte(0x8b); /*MOV EAX, [ESP]*/ + addbyte(0x04 | (REG_EBX << 3)); + addbyte(0x24); + + return REG_EBX; +} + +static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + addbyte(0x8b); /*MOV EBX, [ESP]*/ + addbyte(0x04 | (REG_EBX << 3)); + addbyte(0x24); + addbyte(0x8b); /*MOV ECX, [ESP+4]*/ + addbyte(0x44 | (REG_ECX << 3)); + addbyte(0x24); + addbyte(0x04); + + *host_reg1 = REG_EBX; + *host_reg2 = REG_ECX; +} + + +static double _fp_half = 0.5; + +static void FP_LOAD_ROUNDING() +{ + pclog("npxc %04x\n", npxc); + addbyte(0x8b); /*MOV EDX, npxc*/ + addbyte(0x15); + addlong((uintptr_t)&npxc); + addbyte(0xd9); /*FSTCW [ESP+8]*/ + addbyte(0x7c); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP+12],EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x0c); + addbyte(0xd9); /*FLDCW [ESP+12]*/ + addbyte(0x6c); + addbyte(0x24); + addbyte(0x0c); +} +static void FP_RESTORE_ROUNDING() +{ + addbyte(0xd9); /*FLDCW [ESP+8]*/ + addbyte(0x6c); + addbyte(0x24); + addbyte(0x08); +} + +static int32_t x87_fround32(double b) +{ + int64_t a, c; + + switch ((npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int32_t)floor(b); + case 2: /*Up*/ + return (int32_t)ceil(b); + case 3: /*Chop*/ + return (int32_t)b; + } +} +static int64_t x87_fround64(double b) +{ + int64_t a, c; + + switch ((npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } +} +static int FP_LOAD_REG_INT_W(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + + addbyte(0x89); /*MOV [ESP+8], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + + CALL_FUNC(x87_fround32); + + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + return REG_EBX; +} +static int FP_LOAD_REG_INT(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + + addbyte(0x89); /*MOV [ESP+8], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + + CALL_FUNC(x87_fround32); + + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + return REG_EBX; +} +static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + if (codegen_fpu_loaded_iq[TOP] && (tag[TOP] & TAG_UINT64)) + { + /*If we know the register was loaded with FILDq in this block and + has not been modified, then we can skip most of the conversion + and just load the 64-bit integer representation directly */ + addbyte(0x8b); /*MOV ECX, [ST_i64+EBX*8]*/ + addbyte(0x0c); + addbyte(0xdd); + addlong((uint32_t)ST_i64+4); + addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uint32_t)ST_i64); + + return; + } + + addbyte(0xf6); /*TEST TAG[EBX], TAG_UINT64*/ + addbyte(0x83); + addlong((uintptr_t)tag); + addbyte(TAG_UINT64); + addbyte(0x74); /*JZ +*/ + addbyte(7+7+2); + + addbyte(0x8b); /*MOV ECX, [ST_i64+EBX*8]*/ + addbyte(0x0c); + addbyte(0xdd); + addlong((uint32_t)ST_i64+4); + addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uint32_t)ST_i64); + + addbyte(0xeb); /*JMP done*/ + addbyte(7+4+3+5+2+2+4); + + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + + addbyte(0x89); /*MOV [ESP+8], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + + CALL_FUNC(x87_fround64); + + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x89); /*MOV ECX, EDX*/ + addbyte(0xd1); + + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + *host_reg1 = REG_EBX; + *host_reg2 = REG_ECX; +} + +static void FP_POP() +{ + addbyte(0xa1); /*MOV EAX, TOP*/ + addlong((uintptr_t)&TOP); + addbyte(0xc6); /*MOVB tag[EAX], 3*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(3); + addbyte(0x04); /*ADD AL, 1*/ + addbyte(1); + addbyte(0x24); /*AND AL, 7*/ + addbyte(7); + addbyte(0xa2); /*MOV TOP, AL*/ + addlong((uintptr_t)&TOP); +} + +#define FPU_ADD 0x00 +#define FPU_DIV 0x30 +#define FPU_DIVR 0x38 +#define FPU_MUL 0x08 +#define FPU_SUB 0x20 +#define FPU_SUBR 0x28 + +static void FP_OP_S(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xd8); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); +} +static void FP_OP_D(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x9b); /*FSTCW [ESP+8]*/ + addbyte(0xd9); + addbyte(0x7c); + addbyte(0x24); + addbyte(0x08); + addbyte(0x66); /*MOV AX, [ESP+8]*/ + addbyte(0x8b); + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + addbyte(0x66); /*AND AX, ~(3 << 10)*/ + addbyte(0x25); + addword(~(3 << 10)); + addbyte(0x66); /*OR AX, npxc & (3 << 10)*/ + addbyte(0x0d); + addword(npxc & (3 << 10)); + addbyte(0x66); /*MOV [ESP+12], AX*/ + addbyte(0x89); + addbyte(0x44); + addbyte(0x24); + addbyte(0x0c); + addbyte(0xd9); /*FLDCW [ESP+12]*/ + addbyte(0x6c); + addbyte(0x24); + addbyte(0x0c); + } + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0xd9); /*FLDCW [ESP+8]*/ + addbyte(0x6c); + addbyte(0x24); + addbyte(0x08); + } +} +static void FP_OP_IW(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xde); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); +} +static void FP_OP_IL(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xda); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); +} +static void FP_OP_IQ(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); +} + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +static void FP_COMPARE_S() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xd8); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); +} +static void FP_COMPARE_D() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xdc); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); +} +static void FP_COMPARE_IW() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xde); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); +} +static void FP_COMPARE_IL() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xda); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); +} + +static void FP_OP_REG(int op, int dst, int src) +{ + addbyte(0xa1); /*MOV EAX, TOP*/ + addlong((uintptr_t)&TOP); + addbyte(0xbe); /*MOVL ESI, ST*/ + addlong((uintptr_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (src || dst) + { + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(src ? src : dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + if (src) + { + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xde); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD ST[EAX*8]*/ + addbyte(0x04 | op); + addbyte(0xc6); + addbyte(0xdd); /*FSTP ST[EBX*8]*/ + addbyte(0x1c); + addbyte(0xde); + } + else + { + addbyte(0xdd); /*FLD [ESI+EAX*8]*/ + addbyte(0x04); + addbyte(0xc6); + addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ + addbyte(0xa0); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD ST[EBX*8]*/ + addbyte(0x04 | op); + addbyte(0xde); + addbyte(0xdd); /*FSTP ST[EAX*8]*/ + addbyte(0x1c); + addbyte(0xc6); + } +} + +static void FP_COMPARE_REG(int dst, int src) +{ + addbyte(0xa1); /*MOV EAX, TOP*/ + addlong((uintptr_t)&TOP); + addbyte(0xbe); /*MOVL ESI, ST*/ + addlong((uintptr_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (src || dst) + { + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(src ? src : dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x0d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + + if (src) + { + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xde); + addbyte(0xdc); /*FCOMP ST[EAX*8]*/ + addbyte(0x04 | 0x18); + addbyte(0xc6); + } + else + { + addbyte(0xdd); /*FLD [ESI+EAX*8]*/ + addbyte(0x04); + addbyte(0xc6); + addbyte(0xdc); /*FCOMP ST[EBX*8]*/ + addbyte(0x04 | 0x18); + addbyte(0xde); + } + + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x0d); + addlong(((uintptr_t)&npxs) + 1); +} + +static int ZERO_EXTEND_W_B(int reg) +{ + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static int ZERO_EXTEND_L_B(int reg) +{ + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static int ZERO_EXTEND_L_W(int reg) +{ + addbyte(0x0f); /*MOVZX regl, regw*/ + addbyte(0xb7); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} + +static int SIGN_EXTEND_W_B(int reg) +{ + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static int SIGN_EXTEND_L_B(int reg) +{ + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static int SIGN_EXTEND_L_W(int reg) +{ + addbyte(0x0f); /*MOVSX regl, regw*/ + addbyte(0xbf); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} + +static int COPY_REG(int src_reg) +{ + return src_reg; +} + +static void SET_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x0d); + addlong(addr); + addlong(val); + } + else + { + addbyte(0x80); + addbyte(0x0d); + addlong(addr); + addbyte(val); + } +} +static void CLEAR_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x25); + addlong(addr); + addlong(~val); + } + else + { + addbyte(0x80); + addbyte(0x25); + addlong(addr); + addbyte(~val); + } +} + +#define LOAD_Q_REG_1 REG_EAX +#define LOAD_Q_REG_2 REG_EDX + +static void MMX_ENTER() +{ + if (codegen_mmx_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x05); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(10+7+5+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x05); + addlong((uintptr_t)&oldpc); + addlong(op_old_pc); + addbyte(0xc7); /*MOV [ESP], 7*/ + addbyte(0x04); + addbyte(0x24); + addlong(7); + addbyte(0xe8); /*CALL x86_int*/ + addlong((uint32_t)x86_int - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xc7); /*MOV ISMMX, 1*/ + addbyte(0x05); + addlong((uint32_t)&ismmx); + addlong(1); + addbyte(0xa3); /*MOV TOP, EAX*/ + addlong((uint32_t)&TOP); + addbyte(0xa3); /*MOV tag, EAX*/ + addlong((uint32_t)&tag[0]); + addbyte(0xa3); /*MOV tag+4, EAX*/ + addlong((uint32_t)&tag[4]); + + codegen_mmx_entered = 1; +} + +extern int mmx_ebx_ecx_loaded; + +static int LOAD_MMX_D(int guest_reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = 100; + + addbyte(0x8b); /*MOV EBX, reg*/ + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)&MM[guest_reg].l[0]); + + return host_reg; +} +static int LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) +{ + if (!mmx_ebx_ecx_loaded) + { + *host_reg1 = REG_EBX; + *host_reg2 = REG_ECX; + mmx_ebx_ecx_loaded = 1; + } + else + { + *host_reg1 = REG_EAX; + *host_reg2 = REG_EDX; + } + + addbyte(0x8b); /*MOV EBX, reg*/ + addbyte(0x05 | ((*host_reg1) << 3)); + addlong((uint32_t)&MM[guest_reg].l[0]); + addbyte(0x8b); /*MOV ECX, reg+4*/ + addbyte(0x05 | ((*host_reg2) << 3)); + addlong((uint32_t)&MM[guest_reg].l[1]); +} +static int LOAD_MMX_Q_MMX(int guest_reg) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = guest_reg; + + addbyte(0xf3); /*MOVQ dst_reg,[reg]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x05 | (dst_reg << 3)); + addlong((uint32_t)&MM[guest_reg].q); + + return dst_reg; +} + +static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = 100; + + addbyte(0x66); /*MOVD dst_reg, src_reg1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0 | (dst_reg << 3) | src_reg1); + addbyte(0x66); /*MOVD XMM7, src_reg2*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0 | (7 << 3) | src_reg2); + addbyte(0x66); /*PUNPCKLDQ dst_reg, XMM7*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0 | 7 | (dst_reg << 3)); + + return dst_reg; +} + +static void STORE_MMX_LQ(int guest_reg, int host_reg1) +{ + addbyte(0xC7); /*MOVL [reg],0*/ + addbyte(0x05); + addlong((uint32_t)&MM[guest_reg].l[1]); + addlong(0); + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x05 | (host_reg1 << 3)); + addlong((uint32_t)&MM[guest_reg].l[0]); +} +static void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) +{ + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x05 | (host_reg1 << 3)); + addlong((uint32_t)&MM[guest_reg].l[0]); + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x05 | (host_reg2 << 3)); + addlong((uint32_t)&MM[guest_reg].l[1]); +} +static void STORE_MMX_Q_MMX(int guest_reg, int host_reg) +{ + addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)&MM[guest_reg].q); +} + +#define MMX_x86_OP(name, opcode) \ +static void MMX_ ## name(int dst_reg, int src_reg) \ +{ \ + addbyte(0x66); /*op dst_reg, src_reg*/ \ + addbyte(0x0f); \ + addbyte(opcode); \ + addbyte(0xc0 | (dst_reg << 3) | src_reg); \ +} + +MMX_x86_OP(AND, 0xdb) +MMX_x86_OP(ANDN, 0xdf) +MMX_x86_OP(OR, 0xeb) +MMX_x86_OP(XOR, 0xef) + +MMX_x86_OP(ADDB, 0xfc) +MMX_x86_OP(ADDW, 0xfd) +MMX_x86_OP(ADDD, 0xfe) +MMX_x86_OP(ADDSB, 0xec) +MMX_x86_OP(ADDSW, 0xed) +MMX_x86_OP(ADDUSB, 0xdc) +MMX_x86_OP(ADDUSW, 0xdd) + +MMX_x86_OP(SUBB, 0xf8) +MMX_x86_OP(SUBW, 0xf9) +MMX_x86_OP(SUBD, 0xfa) +MMX_x86_OP(SUBSB, 0xe8) +MMX_x86_OP(SUBSW, 0xe9) +MMX_x86_OP(SUBUSB, 0xd8) +MMX_x86_OP(SUBUSW, 0xd9) + +MMX_x86_OP(PUNPCKLBW, 0x60); +MMX_x86_OP(PUNPCKLWD, 0x61); +MMX_x86_OP(PUNPCKLDQ, 0x62); +MMX_x86_OP(PCMPGTB, 0x64); +MMX_x86_OP(PCMPGTW, 0x65); +MMX_x86_OP(PCMPGTD, 0x66); + +MMX_x86_OP(PCMPEQB, 0x74); +MMX_x86_OP(PCMPEQW, 0x75); +MMX_x86_OP(PCMPEQD, 0x76); + +MMX_x86_OP(PSRLW, 0xd1); +MMX_x86_OP(PSRLD, 0xd2); +MMX_x86_OP(PSRLQ, 0xd3); +MMX_x86_OP(PSRAW, 0xe1); +MMX_x86_OP(PSRAD, 0xe2); +MMX_x86_OP(PSLLW, 0xf1); +MMX_x86_OP(PSLLD, 0xf2); +MMX_x86_OP(PSLLQ, 0xf3); + +MMX_x86_OP(PMULLW, 0xd5); +MMX_x86_OP(PMULHW, 0xe5); +MMX_x86_OP(PMADDWD, 0xf5); + +static void MMX_PACKSSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x63); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PACKUSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PACKSSDW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PUNPCKHBW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static void MMX_PUNPCKHWD(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static void MMX_PUNPCKHDQ(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} + +static void MMX_PSRLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static void MMX_PSRLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static void MMX_PSRLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} diff --git a/src/codegen_ops_xchg.h b/src/codegen_ops_xchg.h new file mode 100644 index 000000000..b95e82f71 --- /dev/null +++ b/src/codegen_ops_xchg.h @@ -0,0 +1,93 @@ +#define OP_XCHG_AX_(reg) \ + static uint32_t ropXCHG_AX_ ## reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int ax_reg, host_reg, temp_reg; \ + \ + ax_reg = LOAD_REG_W(REG_AX); \ + host_reg = LOAD_REG_W(REG_ ## reg); \ + temp_reg = COPY_REG(host_reg); \ + STORE_REG_TARGET_W_RELEASE(ax_reg, REG_ ## reg); \ + STORE_REG_TARGET_W_RELEASE(temp_reg, REG_AX); \ + \ + return op_pc; \ + } + +OP_XCHG_AX_(BX) +OP_XCHG_AX_(CX) +OP_XCHG_AX_(DX) +OP_XCHG_AX_(SI) +OP_XCHG_AX_(DI) +OP_XCHG_AX_(SP) +OP_XCHG_AX_(BP) + +#define OP_XCHG_EAX_(reg) \ + static uint32_t ropXCHG_EAX_ ## reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int eax_reg, host_reg, temp_reg; \ + \ + eax_reg = LOAD_REG_L(REG_EAX); \ + host_reg = LOAD_REG_L(REG_ ## reg); \ + temp_reg = COPY_REG(host_reg); \ + STORE_REG_TARGET_L_RELEASE(eax_reg, REG_ ## reg); \ + STORE_REG_TARGET_L_RELEASE(temp_reg, REG_EAX); \ + \ + return op_pc; \ + } + +OP_XCHG_EAX_(EBX) +OP_XCHG_EAX_(ECX) +OP_XCHG_EAX_(EDX) +OP_XCHG_EAX_(ESI) +OP_XCHG_EAX_(EDI) +OP_XCHG_EAX_(ESP) +OP_XCHG_EAX_(EBP) + +static uint32_t ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ +// #ifdef __amd64__ +// return 0; +// #else + int src_reg, dst_reg, temp_reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + + dst_reg = LOAD_REG_B(fetchdat & 7); + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); + temp_reg = COPY_REG(src_reg); + STORE_REG_TARGET_B_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_B_RELEASE(temp_reg, fetchdat & 7); + + return op_pc + 1; +// #endif +} +static uint32_t ropXCHG_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg, temp_reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + + dst_reg = LOAD_REG_W(fetchdat & 7); + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); + temp_reg = COPY_REG(src_reg); + STORE_REG_TARGET_W_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_W_RELEASE(temp_reg, fetchdat & 7); + + return op_pc + 1; +} +static uint32_t ropXCHG_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg, temp_reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + + dst_reg = LOAD_REG_L(fetchdat & 7); + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); + temp_reg = COPY_REG(src_reg); + STORE_REG_TARGET_L_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_L_RELEASE(temp_reg, fetchdat & 7); + + return op_pc + 1; +} diff --git a/src/codegen_timing_486.c b/src/codegen_timing_486.c new file mode 100644 index 000000000..0cd8c25b7 --- /dev/null +++ b/src/codegen_timing_486.c @@ -0,0 +1,375 @@ +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" + +#define CYCLES(c) (int *)c +#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*e0*/ NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(3), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(6), CYCLES(3), NULL, NULL, CYCLES(4), CYCLES(8), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(4), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(140), CYCLES(196), CYCLES(200), CYCLES(218), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(83), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(257), CYCLES(257) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(9), NULL, CYCLES(28), CYCLES(28), NULL, CYCLES(5), NULL, CYCLES(6) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(3), CYCLES(7), CYCLES(17), CYCLES(3), CYCLES(3), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(8), CYCLES(16), NULL, NULL, CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(3), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(3) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), NULL, CYCLES(5), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(13), NULL, CYCLES(29), CYCLES(29), NULL, CYCLES(10), CYCLES(172), CYCLES(28) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; + +static int timing_count; +static uint8_t last_prefix; + +static inline int COUNT(int *c, int op_32) +{ + if ((uintptr_t)c <= 10000) + return (int)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_486_block_start() +{ +} + +void codegen_timing_486_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_486_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int **timings; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; + if (!mod3) + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + break; + } + } + + timing_count += COUNT(timings[opcode], op_32); + codegen_block_cycles += timing_count; +} + +void codegen_timing_486_block_end() +{ +} + +codegen_timing_t codegen_timing_486 = +{ + codegen_timing_486_start, + codegen_timing_486_prefix, + codegen_timing_486_opcode, + codegen_timing_486_block_start, + codegen_timing_486_block_end +}; diff --git a/src/codegen_timing_686.c b/src/codegen_timing_686.c new file mode 100644 index 000000000..5b2b5eda5 --- /dev/null +++ b/src/codegen_timing_686.c @@ -0,0 +1,1052 @@ +/*Elements taken into account : + - X/Y pairing + - FPU/FXCH pairing + - Prefix decode delay + Elements not taken into account : + - Branch prediction (beyond most simplistic approximation) + - FPU queue + - Out of order execution (beyond most simplistic approximation) +*/ + +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 31) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c) + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (1 << 0) +#define CYCLES_RM (1 << 0) +#define CYCLES_RMW (1 << 0) +#define CYCLES_BRANCH (1 << 0) + +#define CYCLES_MASK ((1 << 7) - 1) + +/*Instruction is MMX shift or pack/unpack instruction*/ +#define MMX_SHIFTPACK (1 << 7) +/*Instruction is MMX multiply instruction*/ +#define MMX_MULTIPLY (1 << 8) + +/*Instruction does not pair*/ +#define PAIR_NP (0 << 29) +/*Instruction pairs in X pipe only*/ +#define PAIR_X (1 << 29) +/*Instruction pairs in X pipe only, and can not pair with a following instruction*/ +#define PAIR_X_BRANCH (2 << 29) +/*Instruction pairs in both X and Y pipes*/ +#define PAIR_XY (3 << 29) + +#define PAIR_MASK (3 << 29) + +/*Instruction has input dependency on register in REG field*/ +#define SRCDEP_REG (1 << 9) +/*Instruction has input dependency on register in R/M field*/ +#define SRCDEP_RM (1 << 10) +/*Instruction modifies register in REG field*/ +#define DSTDEP_REG (1 << 11) +/*Instruction modifies register in R/M field*/ +#define DSTDEP_RM (1 << 12) + +/*Instruction has input dependency on given register*/ +#define SRCDEP_EAX (1 << 13) +#define SRCDEP_ECX (1 << 14) +#define SRCDEP_EDX (1 << 15) +#define SRCDEP_EBX (1 << 16) +#define SRCDEP_ESP (1 << 17) +#define SRCDEP_EBP (1 << 18) +#define SRCDEP_ESI (1 << 19) +#define SRCDEP_EDI (1 << 20) + +/*Instruction modifies given register*/ +#define DSTDEP_EAX (1 << 21) +#define DSTDEP_ECX (1 << 22) +#define DSTDEP_EDX (1 << 23) +#define DSTDEP_EBX (1 << 24) +#define DSTDEP_ESP (1 << 25) +#define DSTDEP_EBP (1 << 26) +#define DSTDEP_ESI (1 << 27) +#define DSTDEP_EDI (1 << 28) + +#define INVALID 0 + +static int prev_full; +static uint32_t prev_opcode; +static uint32_t *prev_timings; +static uint32_t prev_op_32; +static uint32_t prev_regmask; + +#define REGMASK_MMX (1 << 8) + +static uint32_t get_srcdep_mask(uint32_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & SRCDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & SRCDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> 16) & 0xff); + if (data & (MMX_SHIFTPACK | MMX_MULTIPLY)) + mask |= REGMASK_MMX; + + return mask; +} + +static uint32_t get_dstdep_mask(uint32_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & DSTDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & DSTDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> 24) & 0xff); + if (data & (MMX_SHIFTPACK | MMX_MULTIPLY)) + mask |= REGMASK_MMX; + + return mask; +} +static uint32_t opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(7), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(7), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(7), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX | SRCDEP_ESP | DSTDEP_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI | SRCDEP_ESP | DSTDEP_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX | SRCDEP_ESP | DSTDEP_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI | SRCDEP_ESP | DSTDEP_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(9), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(10), PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* Jxx*/ +/*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG, PAIR_XY | CYCLES_REG | DSTDEP_REG, PAIR_XY | CYCLES_REG | DSTDEP_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG | DSTDEP_REG, CYCLES(3), PAIR_XY | CYCLES(1), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), +/* PUSHF POPF SAHF LAHF*/ + PAIR_XY | CYCLES(2) | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(9) | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV*/ +/*b0*/ PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_ESP, PAIR_XY | CYCLES_REG | DSTDEP_EBP, PAIR_XY | CYCLES_REG | DSTDEP_ESI, PAIR_XY | CYCLES_REG | DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(10), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), +/* CALL JMP JMP JMP*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_RMW, INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(9), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(9), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | SRCDEP_REG, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(7), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX | SRCDEP_ESP | DSTDEP_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI | SRCDEP_ESP | DSTDEP_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX | SRCDEP_ESP | DSTDEP_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI | SRCDEP_ESP | DSTDEP_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(9), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(10), PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* Jxx*/ +/*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG | DSTDEP_REG, PAIR_NP | CYCLES(3), PAIR_XY | CYCLES(1), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), +/* PUSHF POPF SAHF LAHF*/ + PAIR_XY | CYCLES(2) | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(9) | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV*/ +/*b0*/ PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_ESP, PAIR_XY | CYCLES_REG | DSTDEP_EBP, PAIR_XY | CYCLES_REG | DSTDEP_ESI, PAIR_XY | CYCLES_REG | DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(13), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), +/* CALL JMP JMP JMP*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_REG, INVALID +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + +/*70*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES(1), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + +/*80*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, + +/*c0*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + +/*d0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + +/*e0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, INVALID, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + +/*f0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, +}; +static uint32_t opcode_timings_0f_mod3[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + +/*70*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES(1), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + +/*80*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + INVALID, PAIR_X | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + +/*e0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, INVALID, + INVALID, PAIR_X | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + +/*f0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + INVALID, PAIR_X | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, +}; + +static uint32_t opcode_timings_shift[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES(3) | DSTDEP_RM, PAIR_XY | CYCLES(4) | DSTDEP_RM, + PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, +}; +static uint32_t opcode_timings_shift_imm[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_imm_mod3[8] = +{ + PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES(3) | DSTDEP_RM, PAIR_XY | CYCLES(4) | DSTDEP_RM, + PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, +}; +static uint32_t opcode_timings_shift_cl[8] = +{ + PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(8) | SRCDEP_ECX, PAIR_XY | CYCLES(9) | SRCDEP_ECX, + PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(2) | SRCDEP_ECX, +}; +static uint32_t opcode_timings_shift_cl_mod3[8] = +{ + PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(8) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(9) | DSTDEP_RM | SRCDEP_ECX, + PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, +}; + +static uint32_t opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(18) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(18) +}; +static uint32_t opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(19,27), PAIR_NP | CYCLES_MULTI(22,30) +}; +static uint32_t opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(19,27), PAIR_NP | CYCLES_MULTI(22,30) +}; +static uint32_t opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), +/* JMP JMP far PUSH*/ + PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_X_BRANCH | CYCLES(1), PAIR_XY | CYCLES(5), +/* JMP JMP far PUSH*/ + PAIR_X_BRANCH | CYCLES(1), PAIR_XY | CYCLES(5), PAIR_XY | CYCLES(2) | SRCDEP_ESP | DSTDEP_ESP, INVALID +}; + +static uint32_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_X | CYCLES(30), PAIR_X | CYCLES(4), PAIR_X | CYCLES(24), PAIR_X | CYCLES(5) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + /*FXCH*/ + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + /*FNOP*/ + PAIR_X | CYCLES(2), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* opFCHS opFABS*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, +/* opFTST opFXAM (oddly low) */ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_X | CYCLES(92), PAIR_X | CYCLES(170), PAIR_X | CYCLES(129), PAIR_X | CYCLES(161), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_X | CYCLES(4), PAIR_X | CYCLES(2), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_X | CYCLES(91), INVALID, PAIR_X | CYCLES(60), PAIR_X | CYCLES(161), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_X | CYCLES(20), PAIR_X | CYCLES(14), PAIR_X | CYCLES(140), PAIR_X | CYCLES(141) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_X | CYCLES(29), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(48) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + INVALID, PAIR_X | CYCLES(5), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDe FSTPe*/ + INVALID, PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_db_mod3[64] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(5), PAIR_X | CYCLES(8), +/* opFNOP opFNOP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint32_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FRSTOR FSAVE FSTSW*/ + PAIR_X | CYCLES(72), INVALID, PAIR_X | CYCLES(67), PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + PAIR_X | CYCLES(3), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FUCOM FUCOMP*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_X | CYCLES(27), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(38) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, PAIR_X | CYCLES(7), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + PAIR_X | CYCLES(8), INVALID, PAIR_X | CYCLES(10), PAIR_X | CYCLES(13), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_X | CYCLES(8), PAIR_X | CYCLES(63), PAIR_X | CYCLES(13) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_X | CYCLES(6), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG +}; + +static int decode_delay; +static uint8_t last_prefix; + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + if (!(c & PAIR_MASK)) + return c & 0xffff; + + return c & CYCLES_MASK; +} + +void codegen_timing_686_block_start() +{ + prev_full = decode_delay = 0; +} + +void codegen_timing_686_start() +{ + decode_delay = 0; + last_prefix = 0; +} + +void codegen_timing_686_prefix(uint8_t prefix, uint32_t fetchdat) +{ + /*6x86 can decode 1 prefix per instruction per clock with no penalty. If + either instruction has more than one prefix then decode is delayed by + one cycle for each additional prefix*/ + decode_delay++; + last_prefix = prefix; +} + +void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int *timings; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; +// pclog("timings 0f\n"); + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + opcode = (opcode >> 3) & 7; +// pclog("timings df\n"); + break; + + default: + switch (opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; + if (!mod3) + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + + case 0xc0: case 0xc1: + timings = mod3 ? opcode_timings_shift_imm_mod3 : opcode_timings_shift_imm; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd0: case 0xd1: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_cl_mod3 : opcode_timings_shift_cl; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; +// pclog("timings normal\n"); + break; + } + } + + if (decode_delay < 0) + decode_delay = 0; + + if (prev_full) + { + uint8_t regmask = get_srcdep_mask(timings[opcode], fetchdat, bit8); + + /*Second instruction in the pair*/ + if ((timings[opcode] & PAIR_MASK) == PAIR_NP) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1; + prev_full = 0; +// pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); + } + else if (((timings[opcode] & PAIR_MASK) == PAIR_X || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + && (prev_timings[opcode] & PAIR_MASK) == PAIR_X) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1; + prev_full = 0; +// pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); + } + else if (prev_regmask & regmask) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1; + prev_full = 0; +// pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); + } + else + { + int t1 = COUNT(prev_timings[prev_opcode], prev_op_32); + int t2 = COUNT(timings[opcode], op_32); + int t_pair = (t1 > t2) ? t1 : t2; + + if (!t_pair) + fatal("Pairable 0 cycles! %02x %02x\n", opcode, prev_opcode); + codegen_block_cycles += t_pair; + decode_delay = (-t_pair) + 1; + + prev_full = 0; +// pclog("Pairable %i %i %i %02x %02x\n", t_pair, t1, t2, opcode, prev_opcode); + return; + } + } + + if (!prev_full) + { + /*First instruction in the pair*/ + if ((timings[opcode] & PAIR_MASK) == PAIR_NP || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + { + /*Instruction not pairable*/ + codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay; + decode_delay = (-COUNT(timings[opcode], op_32)) + 1; +// pclog("Not pairable %i\n", COUNT(timings[opcode], op_32) + decode_delay); + } + else + { + /*Instruction might pair with next*/ +// pclog("Might pair - %02x %02x %08x %08x %08x %p %p %p\n", last_prefix, opcode, timings[opcode], timings[opcode] & PAIR_MASK, PAIR_X_BRANCH, timings, opcode_timings_0f, opcode_timings_0f_mod3); + prev_full = 1; + prev_opcode = opcode; + prev_timings = timings; + prev_op_32 = op_32; + prev_regmask = get_dstdep_mask(timings[opcode], fetchdat, bit8); + return; + } + } +} + +void codegen_timing_686_block_end() +{ + if (prev_full) + { + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + prev_full = 0; + } +} + +codegen_timing_t codegen_timing_686 = +{ + codegen_timing_686_start, + codegen_timing_686_prefix, + codegen_timing_686_opcode, + codegen_timing_686_block_start, + codegen_timing_686_block_end +}; diff --git a/src/codegen_timing_pentium.c b/src/codegen_timing_pentium.c new file mode 100644 index 000000000..31d4cafe7 --- /dev/null +++ b/src/codegen_timing_pentium.c @@ -0,0 +1,1061 @@ +/*Elements taken into account : + - U/V integer pairing + - FPU/FXCH pairing + - Prefix decode delay (including shadowing) + Elements not taken into account : + - Branch prediction (beyond most simplistic approximation) + - PMMX decode queue + - FPU latencies + - MMX latencies +*/ + +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 28) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c | PAIR_NP) + + +static int pair_timings[4][4] = +{ +/* Reg RM RMW Branch*/ +/*Reg*/ {1, 2, 3, 2}, +/*RM*/ {2, 2, 3, 3}, +/*RMW*/ {3, 4, 5, 4}, +/*Branch*/ {-1, -1, -1, -1} +}; + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (0 << 0) +#define CYCLES_RM (1 << 0) +#define CYCLES_RMW (2 << 0) +#define CYCLES_BRANCH (3 << 0) + +#define CYCLES_MASK ((1 << 7) - 1) + +/*Instruction is MMX shift or pack/unpack instruction*/ +#define MMX_SHIFTPACK (1 << 7) +/*Instruction is MMX multiply instruction*/ +#define MMX_MULTIPLY (1 << 8) + +/*Instruction does not pair*/ +#define PAIR_NP (0 << 29) +/*Instruction pairs in U pipe only*/ +#define PAIR_U (1 << 29) +/*Instruction pairs in V pipe only*/ +#define PAIR_V (2 << 29) +/*Instruction pairs in both U and V pipes*/ +#define PAIR_UV (3 << 29) +/*Instruction pairs in U pipe only and only with FXCH*/ +#define PAIR_FX (5 << 29) +/*Instruction is FXCH and only pairs in V pipe with FX pairable instruction*/ +#define PAIR_FXCH (6 << 29) + +#define PAIR_MASK (7 << 29) + +/*Instruction has input dependency on register in REG field*/ +#define SRCDEP_REG (1 << 9) +/*Instruction has input dependency on register in R/M field*/ +#define SRCDEP_RM (1 << 10) +/*Instruction modifies register in REG field*/ +#define DSTDEP_REG (1 << 11) +/*Instruction modifies register in R/M field*/ +#define DSTDEP_RM (1 << 12) + +/*Instruction has input dependency on given register*/ +#define SRCDEP_EAX (1 << 13) +#define SRCDEP_ECX (1 << 14) +#define SRCDEP_EDX (1 << 15) +#define SRCDEP_EBX (1 << 16) +#define SRCDEP_ESP (1 << 17) +#define SRCDEP_EBP (1 << 18) +#define SRCDEP_ESI (1 << 19) +#define SRCDEP_EDI (1 << 20) + +/*Instruction modifies given register*/ +#define DSTDEP_EAX (1 << 21) +#define DSTDEP_ECX (1 << 22) +#define DSTDEP_EDX (1 << 23) +#define DSTDEP_EBX (1 << 24) +#define DSTDEP_ESP (1 << 25) +#define DSTDEP_EBP (1 << 26) +#define DSTDEP_ESI (1 << 27) +#define DSTDEP_EDI (1 << 28) + +#define INVALID 0 + +static int u_pipe_full; +static uint32_t u_pipe_opcode; +static uint32_t *u_pipe_timings; +static uint32_t u_pipe_op_32; +static uint32_t u_pipe_regmask; + +#define REGMASK_SHIFTPACK (1 << 8) +#define REGMASK_MULTIPLY (1 << 8) + +static uint32_t get_srcdep_mask(uint32_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & SRCDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & SRCDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> 16) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + + return mask; +} + +static uint32_t get_dstdep_mask(uint32_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & DSTDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & DSTDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> 24) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + + return mask; +} +static uint32_t opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_U | CYCLES_RMW | SRCDEP_REG, PAIR_U | CYCLES_RMW | SRCDEP_REG, PAIR_U | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_U | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_RMW | SRCDEP_REG, PAIR_U | CYCLES_RMW | SRCDEP_REG, PAIR_U | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_U | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG, PAIR_UV | CYCLES_REG | DSTDEP_REG, PAIR_UV | CYCLES_REG | DSTDEP_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG | DSTDEP_REG, CYCLES(3), PAIR_NP | CYCLES(3), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), + +/* MOV*/ +/*b0*/ PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_ESP, PAIR_UV | CYCLES_REG | DSTDEP_EBP, PAIR_UV | CYCLES_REG | DSTDEP_ESI, PAIR_UV | CYCLES_REG | DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_RMW, INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | SRCDEP_REG, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG | DSTDEP_REG, CYCLES(3), PAIR_NP | CYCLES(3), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), + +/* MOV*/ +/*b0*/ PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_ESP, PAIR_UV | CYCLES_REG | DSTDEP_EBP, PAIR_UV | CYCLES_REG | DSTDEP_ESI, PAIR_UV | CYCLES_REG | DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_REG, INVALID +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + +/*70*/ INVALID, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_NP | CYCLES(100), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + +/*80*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + +/*e0*/ INVALID, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, INVALID, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + +/*f0*/ INVALID, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, +}; +static uint32_t opcode_timings_0f_mod3[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/*70*/ INVALID, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(100), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/*80*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + INVALID, PAIR_UV | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + +/*e0*/ INVALID, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, INVALID, + INVALID, PAIR_UV | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + +/*f0*/ INVALID, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + INVALID, PAIR_UV | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, +}; + +static uint32_t opcode_timings_shift[8] = +{ + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, + PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, +}; + +static uint32_t opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) +}; +static uint32_t opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) +}; +static uint32_t opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) +}; +static uint32_t opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), +/* JMP JMP far PUSH*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), +/* JMP JMP far PUSH*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID +}; + +static uint32_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + PAIR_FX | CYCLES(1), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_NP | CYCLES(32), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(48), PAIR_NP | CYCLES(2) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), + /*FXCH*/ + PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), + PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), + /*FNOP*/ + PAIR_NP | CYCLES(3), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), +/* opFCHS opFABS*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(3), INVALID, INVALID, +/* opFTST opFXAM*/ + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(21), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_NP | CYCLES(2), CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(22), PAIR_NP | CYCLES(100), PAIR_NP | CYCLES(100), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_NP | CYCLES(70), INVALID, PAIR_NP | CYCLES(70), PAIR_NP | CYCLES(50), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(50), PAIR_NP | CYCLES(50) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(42), PAIR_NP | CYCLES(42) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, + INVALID, PAIR_NP | CYCLES(5), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + PAIR_NP | CYCLES(1), INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), +/* FLDe FSTPe*/ + INVALID, PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(3) +}; +static uint32_t opcode_timings_db_mod3[64] = +{ + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(17), +/* opFNOP opFNOP*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint32_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + PAIR_FX | CYCLES(1), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* FRSTOR FSAVE FSTSW*/ + PAIR_NP | CYCLES(70), INVALID, PAIR_NP | CYCLES(127), PAIR_NP | CYCLES(2) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* FUCOM FUCOMP*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(42), PAIR_NP | CYCLES(42) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), INVALID, PAIR_FX | CYCLES(1), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + PAIR_NP | CYCLES(1), INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(148), PAIR_NP | CYCLES(6) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_NP | CYCLES(2), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, + PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG +}; + +static int decode_delay; +static uint8_t last_prefix; + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + if (!(c & PAIR_MASK)) + return c & 0xffff; + if ((c & PAIR_MASK) == PAIR_FX) + return c & 0xffff; + switch (c & CYCLES_MASK) + { + case CYCLES_REG: + return 1; + case CYCLES_RM: + return 2; + case CYCLES_RMW: + return 3; + case CYCLES_BRANCH: + return cpu_hasMMX ? 1 : 2; + } + + fatal("Illegal COUNT %08x\n", c); + + return c; +} + +void codegen_timing_pentium_block_start() +{ + u_pipe_full = decode_delay = 0; +} + +void codegen_timing_pentium_start() +{ +// decode_delay = 0; + last_prefix = 0; +} + +void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if (cpu_hasMMX && prefix == 0x0f) + { + /*On Pentium MMX 0fh prefix is 'free'*/ + last_prefix = prefix; + return; + } + if (cpu_hasMMX && (prefix == 0x66 || prefix == 0x67)) + { + /*On Pentium MMX 66h and 67h prefixes take 2 clocks*/ + decode_delay += 2; + last_prefix = prefix; + return; + } + if (prefix == 0x0f && (opcode & 0xf0) == 0x80) + { + /*On Pentium 0fh prefix is 'free' when used on conditional jumps*/ + last_prefix = prefix; + return; + } + /*On Pentium all prefixes take 1 cycle to decode. Decode may be shadowed + by execution of previous instructions*/ + decode_delay++; + last_prefix = prefix; +} + +void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int *timings; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; +// pclog("timings 0f\n"); + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + opcode = (opcode >> 3) & 7; +// pclog("timings df\n"); + break; + + default: + switch (opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; + if (!mod3) + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + opcode = (fetchdat >> 3) & 7; +// pclog("timings c0\n"); + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; +// pclog("timings normal\n"); + break; + } + } + + if (decode_delay < 0) + decode_delay = 0; + + if (u_pipe_full) + { + uint8_t regmask = get_srcdep_mask(timings[opcode], fetchdat, bit8); + + if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && + (timings[opcode] & PAIR_MASK) != PAIR_FXCH) + goto nopair; + + if ((timings[opcode] & PAIR_MASK) == PAIR_FXCH && + (u_pipe_timings[u_pipe_opcode] & PAIR_MASK) != PAIR_FX) + goto nopair; + + if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && !decode_delay) + { + int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK; + int t2 = timings[opcode] & CYCLES_MASK; + int t_pair; + + if (t1 < 0 || t2 < 0 || t1 > CYCLES_BRANCH || t2 > CYCLES_BRANCH) + fatal("Pair out of range\n"); + + t_pair = pair_timings[t1][t2]; + if (t_pair < 1) + fatal("Illegal pair timings : t1=%i t2=%i u_opcode=%02x v_opcode=%02x\n", t1, t2, u_pipe_opcode, opcode); + +// pclog("Paired timings : t_pair=%i t1=%i t2=%i u_opcode=%02x v_opcode=%02x %08x:%08x\n", t_pair, t1, t2, u_pipe_opcode, opcode, cs, pc); + codegen_block_cycles += t_pair; + decode_delay = (-t_pair) + 1; + + /*Instruction can pair with previous*/ + u_pipe_full = 0; + return; + } +nopair: + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay; + decode_delay = (-COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32)) + 1; + u_pipe_full = 0; +// pclog("Evicited U-pipe timings : t1=%i u_opcode=%02x decode_delay=%i %08x:%08x\n", COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32), u_pipe_opcode, decode_delay, cs, pc); + } + + if ((timings[opcode] & PAIR_U) && !decode_delay) + { + /*Instruction might pair with next*/ + u_pipe_full = 1; + u_pipe_opcode = opcode; + u_pipe_timings = timings; + u_pipe_op_32 = op_32; + u_pipe_regmask = get_dstdep_mask(timings[opcode], fetchdat, bit8); + return; + } + /*Instruction can not pair and must run now*/ + + codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay; + decode_delay = (-COUNT(timings[opcode], op_32)) + 1; +// pclog("Non-pairable timings : %08x t1=%i opcode=%02x mod3=%i decode_delay=%i %08x:%08x %08x %p %p\n", timings[opcode], COUNT(timings[opcode], op_32), opcode, mod3, decode_delay, cs, pc, opcode_timings[0x04], (void *)timings, (void *)opcode_timings); +} + +void codegen_timing_pentium_block_end() +{ + if (u_pipe_full) + { + /*Run previous now*/ + codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay; + u_pipe_full = 0; + } +} + +codegen_timing_t codegen_timing_pentium = +{ + codegen_timing_pentium_start, + codegen_timing_pentium_prefix, + codegen_timing_pentium_opcode, + codegen_timing_pentium_block_start, + codegen_timing_pentium_block_end +}; diff --git a/src/codegen_timing_winchip.c b/src/codegen_timing_winchip.c new file mode 100644 index 000000000..342fbb0b6 --- /dev/null +++ b/src/codegen_timing_winchip.c @@ -0,0 +1,375 @@ +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" + +#define CYCLES(c) (int *)c +#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*e0*/ NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(2), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(7), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(2), CYCLES(2), NULL, NULL, CYCLES(5), CYCLES(7), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(5), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(5), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(300), CYCLES(58), CYCLES(676), CYCLES(355), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(72), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(474), CYCLES(474) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), NULL, CYCLES(8) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(7), CYCLES(18), CYCLES(27), CYCLES(7), CYCLES(7), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(6), CYCLES(8), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(74), CYCLES(74) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(4), CYCLES(6), NULL, NULL, CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(2), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(5) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), NULL, CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), CYCLES(172), CYCLES(8) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; + +static int timing_count; +static uint8_t last_prefix; + +static inline int COUNT(int *c, int op_32) +{ + if ((uintptr_t)c <= 10000) + return (int)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_winchip_block_start() +{ +} + +void codegen_timing_winchip_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int **timings; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; + if (!mod3) + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + break; + } + } + + timing_count += COUNT(timings[opcode], op_32); + codegen_block_cycles += timing_count; +} + +void codegen_timing_winchip_block_end() +{ +} + +codegen_timing_t codegen_timing_winchip = +{ + codegen_timing_winchip_start, + codegen_timing_winchip_prefix, + codegen_timing_winchip_opcode, + codegen_timing_winchip_block_start, + codegen_timing_winchip_block_end +}; diff --git a/src/codegen_x86-64.c b/src/codegen_x86-64.c new file mode 100644 index 000000000..807224de2 --- /dev/null +++ b/src/codegen_x86-64.c @@ -0,0 +1,1247 @@ +#ifdef __amd64__ + +#include +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" + +#include "386_common.h" + +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_ops_x86-64.h" + +#ifdef __linux__ +#include +#include +#endif +#if WIN64 +#include +#endif + + +int codegen_flags_changed = 0; +int codegen_fpu_entered = 0; +int codegen_fpu_loaded_iq[8]; +int codegen_reg_loaded[8]; +x86seg *op_ea_seg; +int op_ssegs; +uint32_t op_old_pc; + +uint32_t recomp_page = -1; + +int host_reg_mapping[NR_HOST_REGS]; +int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; +codeblock_t *codeblock; +codeblock_t **codeblock_hash; +int codegen_mmx_entered = 0; + +int block_current = 0; +static int block_num; +int block_pos; + +int cpu_recomp_flushes, cpu_recomp_flushes_latched; +int cpu_recomp_evicted, cpu_recomp_evicted_latched; +int cpu_recomp_reuse, cpu_recomp_reuse_latched; +int cpu_recomp_removed, cpu_recomp_removed_latched; + +static uint32_t codegen_endpc; + +int codegen_block_cycles; +static int codegen_block_ins; +static int codegen_block_full_ins; + +static uint32_t last_op32; +static x86seg *last_ea_seg; +static int last_ssegs; + +void codegen_init() +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if WIN64 + codeblock = VirtualAlloc(NULL, BLOCK_SIZE * sizeof(codeblock_t), MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); +#endif + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + +#ifdef __linux__ + start = (void *)((long)codeblock & pagemask); + len = ((BLOCK_SIZE * sizeof(codeblock_t)) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif +// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); +} + +void codegen_reset() +{ + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + mem_reset_page_blocks(); +} + +void dump_block() +{ + codeblock_t *block = pages[0x119000 >> 12].block; + + pclog("dump_block:\n"); + while (block) + { + uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); + uint32_t end_pc = (block->endpc & 0xffc) | (block->phys & ~0xfff); + pclog(" %p : %08x-%08x %08x-%08x %p %p\n", (void *)block, start_pc, end_pc, block->pc, block->endpc, (void *)block->prev, (void *)block->next); + if (!block->pc) + fatal("Dead PC=0\n"); + + block = block->next; + } + pclog("dump_block done\n"); +} + +static void delete_block(codeblock_t *block) +{ +// pclog("delete_block: pc=%08x\n", block->pc); + if (block == codeblock_hash[HASH(block->phys)]) + codeblock_hash[HASH(block->phys)] = NULL; + + if (!block->pc) + fatal("Deleting deleted block\n"); + block->pc = 0; + + codeblock_tree_delete(block); + + if (block->prev) + { + block->prev->next = block->next; + if (block->next) + block->next->prev = block->prev; + } + else + { + pages[block->phys >> 12].block = block->next; + if (block->next) + block->next->prev = NULL; + else + mem_flush_write_page(block->phys, 0); + } + if (!block->page_mask2) + { + if (block->prev_2 || block->next_2) + fatal("Invalid block_2\n"); + return; + } + + if (block->prev_2) + { + block->prev_2->next_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = block->prev_2; + } + else + { +// pclog(" pages.block_2=%p 3 %p %p\n", (void *)block->next_2, (void *)block, (void *)pages[block->phys_2 >> 12].block_2); + pages[block->phys_2 >> 12].block_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = NULL; + else + mem_flush_write_page(block->phys_2, 0); + } +} + +void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) +{ + struct codeblock_t *block = page->block; + + while (block) + { + if (mask & block->page_mask) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next) + fatal("Broken 1\n"); + block = block->next; + } + + block = page->block_2; + + while (block) + { + if (mask & block->page_mask2) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next_2) + fatal("Broken 2\n"); + block = block->next_2; + } +} + +void codegen_block_init(uint32_t phys_addr) +{ + codeblock_t *block; + int has_evicted = 0; + page_t *page = &pages[phys_addr >> 12]; + + if (!page->block) + mem_flush_write_page(phys_addr, cs+cpu_state.pc); + + block_current = (block_current + 1) & BLOCK_MASK; + block = &codeblock[block_current]; + +// if (block->pc == 0xb00b4ff5) +// pclog("Init target block\n"); + if (block->pc != 0) + { +// pclog("Reuse block : was %08x now %08x\n", block->pc, cs+pc); + delete_block(block); + cpu_recomp_reuse++; + } + block_num = HASH(phys_addr); + codeblock_hash[block_num] = &codeblock[block_current]; + block->ins = 0; + block->pc = cs + cpu_state.pc; + block->_cs = cs; + block->pnt = block_current; + block->phys = phys_addr; + block->use32 = use32; + block->stack32 = stack32; + block->next = block->prev = NULL; + + block_pos = BLOCK_GPF_OFFSET; +#if WIN64 + addbyte(0x48); /*XOR RCX, RCX*/ + addbyte(0x31); + addbyte(0xc9); + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); +#else + addbyte(0x48); /*XOR RDI, RDI*/ + addbyte(0x31); + addbyte(0xff); + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); +#endif + call(block, (uintptr_t)x86gpf); + while (block_pos < BLOCK_EXIT_OFFSET) + addbyte(0x90); /*NOP*/ + block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ + addbyte(0x48); /*ADDL $40,%rsp*/ + addbyte(0x83); + addbyte(0xC4); + addbyte(0x28); + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5d); /*POP RBP*/ + addbyte(0x5b); /*POP RDX*/ + addbyte(0xC3); /*RET*/ + cpu_block_end = 0; + block_pos = 0; /*Entry code*/ + addbyte(0x53); /*PUSH RBX*/ + addbyte(0x55); /*PUSH RBP*/ + addbyte(0x56); /*PUSH RSI*/ + addbyte(0x57); /*PUSH RDI*/ + addbyte(0x41); /*PUSH R12*/ + addbyte(0x54); + addbyte(0x41); /*PUSH R13*/ + addbyte(0x55); + addbyte(0x41); /*PUSH R14*/ + addbyte(0x56); + addbyte(0x41); /*PUSH R15*/ + addbyte(0x57); + addbyte(0x48); /*SUBL $40,%rsp*/ + addbyte(0x83); + addbyte(0xEC); + addbyte(0x28); + addbyte(0x48); /*MOVL EBP, &EAX*/ + addbyte(0xBD); + addquad((uint64_t)&EAX); + +// pclog("New block %i for %08X %03x\n", block_current, cs+pc, block_num); + + last_op32 = -1; + last_ea_seg = NULL; + last_ssegs = -1; + + codegen_block_cycles = 0; + codegen_timing_block_start(); + + codegen_block_ins = 0; + codegen_block_full_ins = 0; + + recomp_page = phys_addr & ~0xfff; + + codegen_flags_changed = 0; + codegen_fpu_entered = 0; + codegen_mmx_entered = 0; + + codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = + codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; + + _ds.checked = _es.checked = _fs.checked = _gs.checked = (cr0 & 1) ? 0 : 1; + + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; +} + +void codegen_block_remove() +{ + codeblock_t *block = &codeblock[block_current]; +//if ((block->phys & ~0xfff) == 0x119000) pclog("codegen_block_remove %08x\n", block->pc); +// if (block->pc == 0xb00b4ff5) +// pclog("Remove target block\n"); + codeblock_hash[block_num] = NULL; + block->pc = 0;//xffffffff; + cpu_recomp_removed++; +// pclog("Remove block %i\n", block_num); + recomp_page = -1; +} + +void codegen_block_end() +{ + codeblock_t *block = &codeblock[block_current]; + codeblock_t *block_prev = pages[block->phys >> 12].block; + uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); + uint32_t end_pc = ((codegen_endpc + 3) & 0xffc) | (block->phys & ~0xfff); + + block->endpc = codegen_endpc; + +// if (block->pc == 0xb00b4ff5) +// pclog("End target block\n"); + + if (block_prev) + { + block->next = block_prev; + block_prev->prev = block; + pages[block->phys >> 12].block = block; + } + else + { + block->next = NULL; + pages[block->phys >> 12].block = block; + } + + if (block->next) + { +// pclog(" next->pc=%08x\n", block->next->pc); + if (!block->next->pc) + fatal("block->next->pc=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); + } + + block->page_mask = 0; + start_pc = block->pc & 0xffc; + start_pc &= ~PAGE_MASK_MASK; + end_pc = ((block->endpc & 0xffc) + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + if (end_pc > 0xfff || end_pc < start_pc) + end_pc = 0xfff; + start_pc >>= PAGE_MASK_SHIFT; + end_pc >>= PAGE_MASK_SHIFT; + +// pclog("block_end: %08x %08x\n", start_pc, end_pc); + for (; start_pc <= end_pc; start_pc++) + { + block->page_mask |= ((uint64_t)1 << start_pc); +// pclog(" %08x %llx\n", start_pc, block->page_mask); + } + + pages[block->phys >> 12].code_present_mask |= block->page_mask; + + block->phys_2 = -1; + block->page_mask2 = 0; + block->next_2 = block->prev_2 = NULL; + if ((block->pc ^ block->endpc) & ~0xfff) + { + block->phys_2 = get_phys_noabrt(block->endpc); + if (block->phys_2 != -1) + { +// pclog("start block - %08x %08x %p %p %p %08x\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, (void *)pages[block->phys_2 >> 12].block_2, block->phys_2); + + if (pages[block->phys_2 >> 12].block_2 == block) + fatal("Block same\n"); + + block_prev = pages[block->phys_2 >> 12].block_2; + + if (block_prev) + { + block->next_2 = block_prev; + block_prev->prev_2 = block; + pages[block->phys_2 >> 12].block_2 = block; +// pclog(" pages.block_2=%p\n", (void *)block); + } + else + { + block->next_2 = NULL; + pages[block->phys_2 >> 12].block_2 = block; +// pclog(" pages.block_2=%p 2\n", (void *)block); + } + + start_pc = 0; + end_pc = (block->endpc & 0xfff) >> PAGE_MASK_SHIFT; + for (; start_pc <= end_pc; start_pc++) + block->page_mask2 |= ((uint64_t)1 << start_pc); + + if (!pages[block->phys_2 >> 12].block_2) + mem_flush_write_page(block->phys_2, block->endpc); +// pclog("New block - %08x %08x %p %p phys %08x %08x %016llx\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, block->phys, block->phys_2, block->page_mask2); + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { +// pclog(" next_2->pc=%08x\n", block->next_2->pc); + if (!block->next_2->pc) + fatal("block->next_2->pc=0 %p\n", (void *)block->next_2); + } + } + } + +// pclog("block_end: %08x %08x %016llx\n", block->pc, block->endpc, block->page_mask); + + codegen_timing_block_end(); + + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uint32_t)&cycles); + addlong((uint32_t)codegen_block_cycles); + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&cpu_recomp_ins); + addlong(codegen_block_ins); + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + } +#endif + addbyte(0x48); /*ADDL $40,%rsp*/ + addbyte(0x83); + addbyte(0xC4); + addbyte(0x28); + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5d); /*POP RBP*/ + addbyte(0x5b); /*POP RDX*/ + addbyte(0xC3); /*RET*/ + + if (block_pos > BLOCK_GPF_OFFSET) + fatal("Over limit!\n"); +// pclog("End block %i\n", block_num); + + recomp_page = -1; + + codeblock_tree_add(block); +} + +void codegen_flush() +{ + return; +} + +static int opcode_needs_tempc[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*20*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*c0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*e0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*f0*/ +}; + +static int opcode_conditional_jump[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*60*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*d0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*f0*/ +}; + +static int opcode_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/ +}; +int opcode_0f_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /*a0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ + + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/ + 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ +}; + +void codegen_debug() +{ + if (output) + { + pclog("At %04x(%08x):%04x %04x(%08x):%04x es=%08x EAX=%08x BX=%04x ECX=%08x BP=%04x EDX=%08x EDI=%08x\n", CS, cs, cpu_state.pc, SS, ss, ESP, es,EAX, BX,ECX,BP, EDX,EDI); + } +} + +static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + if (!mod && rm == 6) + { + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + int base_reg, index_reg; + + switch (rm) + { + case 0: case 1: case 7: + base_reg = LOAD_REG_W(REG_BX); + break; + case 2: case 3: case 6: + base_reg = LOAD_REG_W(REG_BP); + break; + case 4: + base_reg = LOAD_REG_W(REG_SI); + break; + case 5: + base_reg = LOAD_REG_W(REG_DI); + break; + } + if (!(rm & 4)) + { + if (rm & 1) + index_reg = LOAD_REG_W(REG_DI); + else + index_reg = LOAD_REG_W(REG_SI); + } + base_reg &= 7; + index_reg &= 7; + + switch (mod) + { + case 0: + if (rm & 4) + { + addbyte(0x41); /*MOVZX EAX, base_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xc0 | base_reg); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3)); + } + } + break; + case 1: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm8*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte((fetchdat >> 8) & 0xff); + } + (*op_pc)++; + break; + case 2: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong((fetchdat >> 8) & 0xffff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm16*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3)); + addlong((fetchdat >> 8) & 0xffff); + } + (*op_pc) += 2; + break; + + } + if (mod || !(rm & 4)) + { + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + } + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} +//#if 0 +static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + uint32_t new_eaaddr; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + int base_reg = -1, index_reg = -1; + + (*op_pc)++; + + if (mod || (sib & 7) != 5) + base_reg = LOAD_REG_L(sib & 7) & 7; + + if (((sib >> 3) & 7) != 4) + index_reg = LOAD_REG_L((sib >> 3) & 7) & 7; + + if (index_reg == -1) + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOV EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x44); + addbyte(0x24); + } + else + { + addbyte(0x40 | base_reg); + } + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x84); + addbyte(0x24); + } + else + { + addbyte(0x80 | base_reg); + } + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + else + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + if (sib >> 6) + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*scale*/ + addbyte(0x42); + addbyte(0x8d); + addbyte(0x04); + addbyte(0x05 | (sib & 0xc0) | (index_reg << 3)); + addlong(new_eaaddr); + } + else + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | index_reg); + addlong(new_eaaddr); + } + (*op_pc) += 4; + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + } + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + addbyte(0x05); + addlong(stack_offset); + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + } + else + { + int base_reg; + + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + base_reg = LOAD_REG_L(rm) & 7; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, base_reg+imm32*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong(new_eaaddr); + (*op_pc) += 4; + } + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + } + else + { + addbyte(0x44); /*MOV eaaddr, base_reg*/ + addbyte(0x89); + addbyte(4 | (base_reg << 3)); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + } + } + return op_ea_seg; +} +//#endif +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t op_32 = use32; + uint32_t op_pc = new_pc; + OpFn *op_table = x86_dynarec_opcodes; + RecompOpFn *recomp_op_table = recomp_opcodes; + int opcode_shift = 0; + int opcode_mask = 0x3ff; + int over = 0; + int pc_off = 0; + int test_modrm = 1; + int c; + + op_ea_seg = &_ds; + op_ssegs = 0; + op_old_pc = old_pc; + + for (c = 0; c < NR_HOST_REGS; c++) + host_reg_mapping[c] = -1; + for (c = 0; c < NR_HOST_XMM_REGS; c++) + host_reg_xmm_mapping[c] = -1; + + codegen_timing_start(); + + while (!over) + { + switch (opcode) + { + case 0x0f: + op_table = x86_dynarec_opcodes_0f; + recomp_op_table = recomp_opcodes_0f; + over = 1; + break; + + case 0x26: /*ES:*/ + op_ea_seg = &_es; + op_ssegs = 1; + break; + case 0x2e: /*CS:*/ + op_ea_seg = &_cs; + op_ssegs = 1; + break; + case 0x36: /*SS:*/ + op_ea_seg = &_ss; + op_ssegs = 1; + break; + case 0x3e: /*DS:*/ + op_ea_seg = &_ds; + op_ssegs = 1; + break; + case 0x64: /*FS:*/ + op_ea_seg = &_fs; + op_ssegs = 1; + break; + case 0x65: /*GS:*/ + op_ea_seg = &_gs; + op_ssegs = 1; + break; + + case 0x66: /*Data size select*/ + op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); + break; + case 0x67: /*Address size select*/ + op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); + break; + + case 0xd8: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; + recomp_op_table = recomp_opcodes_d8; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xd9: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; + recomp_op_table = recomp_opcodes_d9; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xda: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; + recomp_op_table = recomp_opcodes_da; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdb: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; + recomp_op_table = recomp_opcodes_db; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdc: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; + recomp_op_table = recomp_opcodes_dc; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdd: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; + recomp_op_table = recomp_opcodes_dd; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xde: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; + recomp_op_table = recomp_opcodes_de; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdf: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; + recomp_op_table = recomp_opcodes_df; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + + case 0xf0: /*LOCK*/ + break; + + default: + goto generate_call; + } + fetchdat = fastreadl(cs + op_pc); + codegen_timing_prefix(opcode, fetchdat); + if (abrt) + return; + opcode = fetchdat & 0xff; + if (!pc_off) + fetchdat >>= 8; + op_pc++; + } + +generate_call: + codegen_timing_opcode(opcode, fetchdat, op_32); + + if ((op_table == x86_dynarec_opcodes && + ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || + (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || + (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30))) || + (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80)))) + { + /*Opcode is likely to cause block to exit, update cycle count*/ + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uint32_t)&cycles); + addlong((uint32_t)codegen_block_cycles); + codegen_block_cycles = 0; + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&cpu_recomp_ins); + addlong(codegen_block_ins); + codegen_block_ins = 0; + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + codegen_block_full_ins = 0; + } +#endif + } + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) + { + uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); + if (new_pc) + { + if (new_pc != -1) + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, new_pc); + + codegen_block_ins++; + block->ins++; + codegen_block_full_ins++; + codegen_endpc = (cs + cpu_state.pc) + 8; + + return; + } + } + + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; +// if (output) +// pclog("Generate call at %08X %02X %08X %02X %08X %08X %08X %08X %08X %02X %02X %02X %02X\n", &codeblock[block_current][block_pos], opcode, new_pc, ram[old_pc], EAX, EBX, ECX, EDX, ESI, ram[0x7bd2+6],ram[0x7bd2+7],ram[0x7bd2+8],ram[0x7bd2+9]); + if (opcode_needs_tempc[opcode]) + { + addbyte(0x8b); /*MOVL (flags), %eax*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&flags); + addbyte(0x83); /*ANDL $1, %eax*/ + addbyte(0xe0); + addbyte(0x01); + addbyte(0x89); /*MOVL %eax, (tempc)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&tempc); + } + if (op_ssegs != last_ssegs) + { + last_ssegs = op_ssegs; + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&ssegs); + addlong(op_ssegs); + } +//#if 0 + if ((!test_modrm || + (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]))/* && !(op_32 & 0x200)*/) + { + int stack_offset = 0; + + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ + stack_offset = (op_32 & 0x100) ? 4 : 2; + + mod = (fetchdat >> 6) & 3; + reg = (fetchdat >> 3) & 7; + rm = fetchdat & 7; + + addbyte(0xC7); /*MOVL $mod,(mod)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&mod); + addlong(mod); + addbyte(0xC7); /*MOVL $reg,(reg)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)®); + addlong(reg); + addbyte(0xC7); /*MOVL $rm,(rm)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&rm); + addlong(rm); + + op_pc += pc_off; + if (mod != 3 && !(op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_16_long(op_ea_seg, fetchdat, op_ssegs, &op_pc); + if (mod != 3 && (op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); + op_pc -= pc_off; + } +//#endif +// if (op_ea_seg != last_ea_seg) +// { +// last_ea_seg = op_ea_seg; + addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&ea_seg); + addlong((uint32_t)op_ea_seg); +// } + + + addbyte(0xC7); /*MOVL [pc],new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc + pc_off); + addbyte(0xC7); /*MOVL $old_pc,(oldpc)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&oldpc); + addlong(old_pc); + if (op_32 != last_op32) + { + last_op32 = op_32; + addbyte(0xC7); /*MOVL $use32,(op32)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&op32); + addlong(op_32); + } + + load_param_1_32(block, fetchdat); + call(block, (uintptr_t)op); + + codegen_block_ins++; + + block->ins++; + + addbyte(0x85); /*OR %eax, %eax*/ + addbyte(0xc0); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); + +// call(block, codegen_debug); + + codegen_endpc = (cs + cpu_state.pc) + 8; +} + +void codegen_check_abrt() +{ + codeblock_t *block = &codeblock[block_current]; +// pclog("Generate check abrt at %08X\n", &codeblock[block_current][block_pos]); + addbyte(0xf7); addbyte(0x04); /*TESTL $-1, (abrt)*/ + addbyte(0x25); + addlong((uint32_t)&abrt); addlong(0xffffffff); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); +} + +#endif diff --git a/src/codegen_x86-64.h b/src/codegen_x86-64.h new file mode 100644 index 000000000..29c09ac4f --- /dev/null +++ b/src/codegen_x86-64.h @@ -0,0 +1,21 @@ +#define BLOCK_SIZE 0x4000 +#define BLOCK_MASK 0x3fff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_EXIT_OFFSET 0x7e0 +#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20) + +enum +{ + OP_RET = 0xc3 +}; + +#define NR_HOST_REGS 3 +extern int host_reg_mapping[NR_HOST_REGS]; +#define NR_HOST_XMM_REGS 7 +extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; diff --git a/src/codegen_x86.c b/src/codegen_x86.c new file mode 100644 index 000000000..a1d1778de --- /dev/null +++ b/src/codegen_x86.c @@ -0,0 +1,1048 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" + +#include "386_common.h" + +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_ops_x86.h" + +#ifdef __linux__ +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +int mmx_ebx_ecx_loaded; +int codegen_flags_changed = 0; +int codegen_fpu_entered = 0; +int codegen_mmx_entered = 0; +int codegen_fpu_loaded_iq[8]; +x86seg *op_ea_seg; +int op_ssegs; +uint32_t op_old_pc; + +uint32_t recomp_page = -1; + +int host_reg_mapping[NR_HOST_REGS]; +int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; +codeblock_t *codeblock; +codeblock_t **codeblock_hash; + + +int block_current = 0; +static int block_num; +int block_pos; + +int cpu_recomp_flushes, cpu_recomp_flushes_latched; +int cpu_recomp_evicted, cpu_recomp_evicted_latched; +int cpu_recomp_reuse, cpu_recomp_reuse_latched; +int cpu_recomp_removed, cpu_recomp_removed_latched; + +static uint32_t codegen_endpc; + +int codegen_block_cycles; +static int codegen_block_ins; +static int codegen_block_full_ins; + +static uint32_t last_op32; +static x86seg *last_ea_seg; +static int last_ssegs; + +void codegen_init() +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if defined WIN32 || defined _WIN32 || defined _WIN32 + codeblock = VirtualAlloc(NULL, BLOCK_SIZE * sizeof(codeblock_t), MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); +#endif + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + +#ifdef __linux__ + start = (void *)((long)codeblock & pagemask); + len = ((BLOCK_SIZE * sizeof(codeblock_t)) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif +// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); +} + +void codegen_reset() +{ + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + mem_reset_page_blocks(); +} + +void dump_block() +{ + codeblock_t *block = pages[0x119000 >> 12].block; + + pclog("dump_block:\n"); + while (block) + { + uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); + uint32_t end_pc = (block->endpc & 0xffc) | (block->phys & ~0xfff); + pclog(" %p : %08x-%08x %08x-%08x %p %p\n", (void *)block, start_pc, end_pc, block->pc, block->endpc, (void *)block->prev, (void *)block->next); + if (!block->pc) + fatal("Dead PC=0\n"); + + block = block->next; + } + pclog("dump_block done\n"); +} + +static void delete_block(codeblock_t *block) +{ +// pclog("delete_block: pc=%08x\n", block->pc); + if (block == codeblock_hash[HASH(block->phys)]) + codeblock_hash[HASH(block->phys)] = NULL; + + if (!block->pc) + fatal("Deleting deleted block\n"); + block->pc = 0; + + codeblock_tree_delete(block); + + if (block->prev) + { + block->prev->next = block->next; + if (block->next) + block->next->prev = block->prev; + } + else + { + pages[block->phys >> 12].block = block->next; + if (block->next) + block->next->prev = NULL; + else + mem_flush_write_page(block->phys, 0); + } + if (!block->page_mask2) + { + if (block->prev_2 || block->next_2) + fatal("Invalid block_2\n"); + return; + } + + if (block->prev_2) + { + block->prev_2->next_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = block->prev_2; + } + else + { +// pclog(" pages.block_2=%p 3 %p %p\n", (void *)block->next_2, (void *)block, (void *)pages[block->phys_2 >> 12].block_2); + pages[block->phys_2 >> 12].block_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = NULL; + else + mem_flush_write_page(block->phys_2, 0); + } +} + +void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) +{ + struct codeblock_t *block = page->block; + + while (block) + { + if (mask & block->page_mask) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next) + fatal("Broken 1\n"); + block = block->next; + } + + block = page->block_2; + + while (block) + { + if (mask & block->page_mask2) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next_2) + fatal("Broken 2\n"); + block = block->next_2; + } +} + +void codegen_block_init(uint32_t phys_addr) +{ + codeblock_t *block; + int has_evicted = 0; + page_t *page = &pages[phys_addr >> 12]; + + if (!page->block) + mem_flush_write_page(phys_addr, cs+cpu_state.pc); + + block_current = (block_current + 1) & BLOCK_MASK; + block = &codeblock[block_current]; + +// if (block->pc == 0xb00b4ff5) +// pclog("Init target block\n"); + if (block->pc != 0) + { +// pclog("Reuse block : was %08x now %08x\n", block->pc, cs+pc); + delete_block(block); + cpu_recomp_reuse++; + } + block_num = HASH(phys_addr); + codeblock_hash[block_num] = &codeblock[block_current]; + block->ins = 0; + block->pc = cs + cpu_state.pc; + block->_cs = cs; + block->pnt = block_current; + block->phys = phys_addr; + block->use32 = use32; + block->stack32 = stack32; + block->next = block->prev = NULL; + + block_pos = BLOCK_GPF_OFFSET; + addbyte(0xc7); /*MOV [ESP],0*/ + addbyte(0x04); + addbyte(0x24); + addlong(0); + addbyte(0xc7); /*MOV [ESP+4],0*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addlong(0); + addbyte(0xe8); /*CALL x86gpf*/ + addlong((uint32_t)x86gpf - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ + addbyte(0x83); /*ADDL $16,%esp*/ + addbyte(0xC4); + addbyte(0x10); + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5d); /*POP EBP*/ + addbyte(0x5b); /*POP EDX*/ + addbyte(0xC3); /*RET*/ + cpu_block_end = 0; + block_pos = 0; /*Entry code*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0x55); /*PUSH EBP*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0x57); /*PUSH EDI*/ + addbyte(0x83); /*SUBL $16,%esp*/ + addbyte(0xEC); + addbyte(0x10); + addbyte(0xBD); /*MOVL EBP, &EAX*/ + addlong((uint32_t)&EAX); + +// pclog("New block %i for %08X %03x\n", block_current, cs+pc, block_num); + + last_op32 = -1; + last_ea_seg = NULL; + last_ssegs = -1; + + codegen_block_cycles = 0; + codegen_timing_block_start(); + + codegen_block_ins = 0; + codegen_block_full_ins = 0; + + recomp_page = phys_addr & ~0xfff; + + codegen_flags_changed = 0; + codegen_fpu_entered = 0; + codegen_mmx_entered = 0; + + codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = + codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; + + _ds.checked = _es.checked = _fs.checked = _gs.checked = (cr0 & 1) ? 0 : 1; +} + +void codegen_block_remove() +{ + codeblock_t *block = &codeblock[block_current]; +//if ((block->phys & ~0xfff) == 0x119000) pclog("codegen_block_remove %08x\n", block->pc); +// if (block->pc == 0xb00b4ff5) +// pclog("Remove target block\n"); + codeblock_hash[block_num] = NULL; + block->pc = 0;//xffffffff; + cpu_recomp_removed++; +// pclog("Remove block %i\n", block_num); + recomp_page = -1; +} + +void codegen_block_end() +{ + codeblock_t *block = &codeblock[block_current]; + codeblock_t *block_prev = pages[block->phys >> 12].block; + uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); + uint32_t end_pc = ((codegen_endpc + 3) & 0xffc) | (block->phys & ~0xfff); + + block->endpc = codegen_endpc; + +// if (block->pc == 0xb00b4ff5) +// pclog("End target block\n"); + + if (block_prev) + { + block->next = block_prev; + block_prev->prev = block; + pages[block->phys >> 12].block = block; + } + else + { + block->next = NULL; + pages[block->phys >> 12].block = block; + } + + if (block->next) + { +// pclog(" next->pc=%08x\n", block->next->pc); + if (!block->next->pc) + fatal("block->next->pc=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); + } + + block->page_mask = 0; + start_pc = block->pc & 0xffc; + start_pc &= ~PAGE_MASK_MASK; + end_pc = ((block->endpc & 0xffc) + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + if (end_pc > 0xfff || end_pc < start_pc) + end_pc = 0xfff; + start_pc >>= PAGE_MASK_SHIFT; + end_pc >>= PAGE_MASK_SHIFT; + +// pclog("block_end: %08x %08x\n", start_pc, end_pc); + for (; start_pc <= end_pc; start_pc++) + { + block->page_mask |= ((uint64_t)1 << start_pc); +// pclog(" %08x %llx\n", start_pc, block->page_mask); + } + + pages[block->phys >> 12].code_present_mask |= block->page_mask; + + block->phys_2 = -1; + block->page_mask2 = 0; + block->next_2 = block->prev_2 = NULL; + if ((block->pc ^ block->endpc) & ~0xfff) + { + block->phys_2 = get_phys_noabrt(block->endpc); + if (block->phys_2 != -1) + { +// pclog("start block - %08x %08x %p %p %p %08x\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, (void *)pages[block->phys_2 >> 12].block_2, block->phys_2); + + if (pages[block->phys_2 >> 12].block_2 == block) + fatal("Block same\n"); + + block_prev = pages[block->phys_2 >> 12].block_2; + + if (block_prev) + { + block->next_2 = block_prev; + block_prev->prev_2 = block; + pages[block->phys_2 >> 12].block_2 = block; +// pclog(" pages.block_2=%p\n", (void *)block); + } + else + { + block->next_2 = NULL; + pages[block->phys_2 >> 12].block_2 = block; +// pclog(" pages.block_2=%p 2\n", (void *)block); + } + + start_pc = 0; + end_pc = (block->endpc & 0xfff) >> PAGE_MASK_SHIFT; + for (; start_pc <= end_pc; start_pc++) + block->page_mask2 |= ((uint64_t)1 << start_pc); + + if (!pages[block->phys_2 >> 12].block_2) + mem_flush_write_page(block->phys_2, block->endpc); +// pclog("New block - %08x %08x %p %p phys %08x %08x %016llx\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, block->phys, block->phys_2, block->page_mask2); + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { +// pclog(" next_2->pc=%08x\n", block->next_2->pc); + if (!block->next_2->pc) + fatal("block->next_2->pc=0 %p\n", (void *)block->next_2); + } + } + } + +// pclog("block_end: %08x %08x %016llx\n", block->pc, block->endpc, block->page_mask); + + codegen_timing_block_end(); + + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uint32_t)&cycles); + addlong((uint32_t)codegen_block_cycles); + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_ins); + addlong(codegen_block_ins); + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + } +#endif + addbyte(0x83); /*ADDL $16,%esp*/ + addbyte(0xC4); + addbyte(0x10); + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5d); /*POP EBP*/ + addbyte(0x5b); /*POP EDX*/ + addbyte(0xC3); /*RET*/ + + if (block_pos > BLOCK_GPF_OFFSET) + fatal("Over limit!\n"); +// pclog("End block %i\n", block_num); + + recomp_page = -1; + + codeblock_tree_add(block); +} + +void codegen_flush() +{ + return; +} + +static int opcode_needs_tempc[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*20*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*c0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*e0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*f0*/ +}; + +static int opcode_conditional_jump[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*60*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*d0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*f0*/ +}; + +static int opcode_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/ +}; +int opcode_0f_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /*a0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ + + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/ + 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ +}; + +void codegen_debug() +{ + if (output) + { + pclog("At %04x(%08x):%04x %04x(%08x):%04x es=%08x EAX=%08x BX=%04x ECX=%08x BP=%04x EDX=%08x EDI=%08x\n", CS, cs, cpu_state.pc, SS, ss, ESP, es,EAX, BX,ECX,BP, EDX,EDI); + } +} + +static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + if (!mod && rm == 6) + { + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x05); + addlong((uint32_t)&eaaddr); + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + switch (mod) + { + case 0: + addbyte(0xa1); /*MOVL *mod1add[0][rm], %eax*/ + addlong((uint32_t)mod1add[0][rm]); + addbyte(0x03); /*ADDL *mod1add[1][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + break; + case 1: + addbyte(0xb8); /*MOVL ,%eax*/ + addlong((uint32_t)(int8_t)(rmdat >> 8));// pc++; + addbyte(0x03); /*ADDL *mod1add[0][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[0][rm]); + addbyte(0x03); /*ADDL *mod1add[1][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + (*op_pc)++; + break; + case 2: + addbyte(0xb8); /*MOVL ,%eax*/ + addlong((fetchdat >> 8) & 0xffff);// pc++; + addbyte(0x03); /*ADDL *mod1add[0][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[0][rm]); + addbyte(0x03); /*ADDL *mod1add[1][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + (*op_pc) += 2; + break; + } + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + addbyte(0xa3); + addlong((uint32_t)&eaaddr); + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} + +static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + uint32_t new_eaaddr; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + (*op_pc)++; + + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL ,%eax*/ + addlong(new_eaaddr);// pc++; + (*op_pc) += 4; + } + else + { + addbyte(0x8b); /*MOVL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[sib & 7].l - (uintptr_t)&cpu_state); + } + break; + case 1: + new_eaaddr = (uint32_t)(int8_t)((fetchdat >> 16) & 0xff); + addbyte(0xb8); /*MOVL new_eaaddr, %eax*/ + addlong(new_eaaddr); + addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[sib & 7].l - (uintptr_t)&cpu_state); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL new_eaaddr, %eax*/ + addlong(new_eaaddr); + addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[sib & 7].l - (uintptr_t)&cpu_state); + (*op_pc) += 4; + break; + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + addbyte(0x05); + addlong(stack_offset); + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + if (((sib >> 3) & 7) != 4) + { + switch (sib >> 6) + { + case 0: + addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[(sib >> 3) & 7].l - (uintptr_t)&cpu_state); + break; + case 1: + addbyte(0x8B); addbyte(0x5D); addbyte((uintptr_t)&cpu_state.regs[(sib >> 3) & 7].l - (uintptr_t)&cpu_state); /*MOVL armregs[RD],%ebx*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + break; + case 2: + addbyte(0x8B); addbyte(0x5D); addbyte((uintptr_t)&cpu_state.regs[(sib >> 3) & 7].l - (uintptr_t)&cpu_state); /*MOVL armregs[RD],%ebx*/ + addbyte(0xC1); addbyte(0xE3); addbyte(2); /*SHL $2,%ebx*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + break; + case 3: + addbyte(0x8B); addbyte(0x5D); addbyte((uintptr_t)&cpu_state.regs[(sib >> 3) & 7].l - (uintptr_t)&cpu_state); /*MOVL armregs[RD],%ebx*/ + addbyte(0xC1); addbyte(0xE3); addbyte(3); /*SHL $2,%ebx*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + break; + } + } + addbyte(0xa3); + addlong((uint32_t)&eaaddr); + } + else + { + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ + addbyte(0x05); + addlong((uint32_t)&eaaddr); + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + addbyte(0x8b); /*MOVL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[rm].l - (uintptr_t)&cpu_state); +// addbyte(0xa1); /*MOVL regs[rm].l, %eax*/ +// addlong((uint32_t)&cpu_state.regs[rm].l); + eaaddr = cpu_state.regs[rm].l; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x05); + addlong((uint32_t)(int8_t)(fetchdat >> 8)); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x05); + addlong(new_eaaddr); + (*op_pc) += 4; + } + } + addbyte(0xa3); + addlong((uint32_t)&eaaddr); + } + return op_ea_seg; +} + +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t op_32 = use32; + uint32_t op_pc = new_pc; + OpFn *op_table = x86_dynarec_opcodes; + RecompOpFn *recomp_op_table = recomp_opcodes; + int opcode_shift = 0; + int opcode_mask = 0x3ff; + int over = 0; + int pc_off = 0; + int test_modrm = 1; + int c; + + op_ea_seg = &_ds; + op_ssegs = 0; + op_old_pc = old_pc; + + for (c = 0; c < NR_HOST_REGS; c++) + host_reg_mapping[c] = -1; + mmx_ebx_ecx_loaded = 0; + for (c = 0; c < NR_HOST_XMM_REGS; c++) + host_reg_xmm_mapping[c] = -1; + + codegen_timing_start(); + + while (!over) + { + switch (opcode) + { + case 0x0f: + op_table = x86_dynarec_opcodes_0f; + recomp_op_table = recomp_opcodes_0f; + over = 1; + break; + + case 0x26: /*ES:*/ + op_ea_seg = &_es; + op_ssegs = 1; + break; + case 0x2e: /*CS:*/ + op_ea_seg = &_cs; + op_ssegs = 1; + break; + case 0x36: /*SS:*/ + op_ea_seg = &_ss; + op_ssegs = 1; + break; + case 0x3e: /*DS:*/ + op_ea_seg = &_ds; + op_ssegs = 1; + break; + case 0x64: /*FS:*/ + op_ea_seg = &_fs; + op_ssegs = 1; + break; + case 0x65: /*GS:*/ + op_ea_seg = &_gs; + op_ssegs = 1; + break; + + case 0x66: /*Data size select*/ + op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); + break; + case 0x67: /*Address size select*/ + op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); + break; + + case 0xd8: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; + recomp_op_table = recomp_opcodes_d8; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xd9: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; + recomp_op_table = recomp_opcodes_d9; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xda: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; + recomp_op_table = recomp_opcodes_da; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdb: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; + recomp_op_table = recomp_opcodes_db; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdc: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; + recomp_op_table = recomp_opcodes_dc; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdd: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; + recomp_op_table = recomp_opcodes_dd; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xde: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; + recomp_op_table = recomp_opcodes_de; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdf: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; + recomp_op_table = recomp_opcodes_df; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + + case 0xf0: /*LOCK*/ + break; + + default: + goto generate_call; + } + fetchdat = fastreadl(cs + op_pc); + codegen_timing_prefix(opcode, fetchdat); + if (abrt) + return; + opcode = fetchdat & 0xff; + if (!pc_off) + fetchdat >>= 8; + + op_pc++; + } + +generate_call: + codegen_timing_opcode(opcode, fetchdat, op_32); + + if ((op_table == x86_dynarec_opcodes && + ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || + (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || + (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30))) || + (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80)))) + { + /*Opcode is likely to cause block to exit, update cycle count*/ + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uint32_t)&cycles); + addlong((uint32_t)codegen_block_cycles); + codegen_block_cycles = 0; + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_ins); + addlong(codegen_block_ins); + codegen_block_ins = 0; + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + codegen_block_full_ins = 0; + } +#endif + } + + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) + { + uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); + if (new_pc) + { + if (new_pc != -1) + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, new_pc); + + codegen_block_ins++; + block->ins++; + codegen_block_full_ins++; + codegen_endpc = (cs + cpu_state.pc) + 8; + + return; + } + } + + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; +// if (output) +// pclog("Generate call at %08X %02X %08X %02X %08X %08X %08X %08X %08X %02X %02X %02X %02X\n", &codeblock[block_current][block_pos], opcode, new_pc, ram[old_pc], EAX, EBX, ECX, EDX, ESI, ram[0x7bd2+6],ram[0x7bd2+7],ram[0x7bd2+8],ram[0x7bd2+9]); + if (opcode_needs_tempc[opcode]) + { + addbyte(0xa1); /*MOVL (flags), %eax*/ + addlong((uint32_t)&flags); + addbyte(0x83); /*ANDL $1, %eax*/ + addbyte(0xe0); + addbyte(0x01); + addbyte(0xa3); /*MOVL %eax, (tempc)*/ + addlong((uint32_t)&tempc); + } + if (op_ssegs != last_ssegs) + { + last_ssegs = op_ssegs; + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x05); + addlong((uint32_t)&ssegs); + addlong(op_ssegs); + } + + if (!test_modrm || + (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode])) + { + int stack_offset = 0; + + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ + stack_offset = (op_32 & 0x100) ? 4 : 2; + + mod = (fetchdat >> 6) & 3; + reg = (fetchdat >> 3) & 7; + rm = fetchdat & 7; + + addbyte(0xC7); /*MOVL $mod,(mod)*/ + addbyte(0x05); + addlong((uint32_t)&mod); + addlong(mod); + addbyte(0xC7); /*MOVL $reg,(reg)*/ + addbyte(0x05); + addlong((uint32_t)®); + addlong(reg); + addbyte(0xC7); /*MOVL $rm,(rm)*/ + addbyte(0x05); + addlong((uint32_t)&rm); + addlong(rm); + + op_pc += pc_off; + if (mod != 3 && !(op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_16_long(op_ea_seg, fetchdat, op_ssegs, &op_pc); + if (mod != 3 && (op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); + op_pc -= pc_off; + } + +// if (op_ea_seg != last_ea_seg) +// { +// last_ea_seg = op_ea_seg; + addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ + addbyte(0x05); + addlong((uint32_t)&ea_seg); + addlong((uint32_t)op_ea_seg); +// } + + addbyte(0xC7); /*MOVL pc,new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc + pc_off); + + addbyte(0xC7); /*MOVL $old_pc,(oldpc)*/ + addbyte(0x05); + addlong((uint32_t)&oldpc); + addlong(old_pc); + if (op_32 != last_op32) + { + last_op32 = op_32; + addbyte(0xC7); /*MOVL $use32,(op32)*/ + addbyte(0x05); + addlong((uint32_t)&op32); + addlong(op_32); + } + + addbyte(0xC7); /*MOVL $fetchdat,(%esp)*/ + addbyte(0x04); + addbyte(0x24); + addlong(fetchdat); + + addbyte(0xE8); /*CALL*/ + addlong(((uint8_t *)op - (uint8_t *)(&block->data[block_pos + 4]))); + + codegen_block_ins++; + + block->ins++; + + addbyte(0x09); /*OR %eax, %eax*/ + addbyte(0xc0); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); + +// addbyte(0xE8); /*CALL*/ +// addlong(((uint8_t *)codegen_debug - (uint8_t *)(&block->data[block_pos + 4]))); + + codegen_endpc = (cs + cpu_state.pc) + 8; +} + +void codegen_check_abrt() +{ + codeblock_t *block = &codeblock[block_current]; +// pclog("Generate check abrt at %08X\n", &codeblock[block_current][block_pos]); + addbyte(0x83); addbyte(0x3d); /*CMP abrt, 0*/ + addlong((uint32_t)&abrt); addbyte(0); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); +} + +#endif diff --git a/src/codegen_x86.h b/src/codegen_x86.h new file mode 100644 index 000000000..e512679db --- /dev/null +++ b/src/codegen_x86.h @@ -0,0 +1,21 @@ +#define BLOCK_SIZE 0x4000 +#define BLOCK_MASK 0x3fff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_EXIT_OFFSET 0x7f0 +#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20) + +enum +{ + OP_RET = 0xc3 +}; + +#define NR_HOST_REGS 3 +extern int host_reg_mapping[NR_HOST_REGS]; +#define NR_HOST_XMM_REGS 7 +extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; diff --git a/src/compaq.c b/src/compaq.c new file mode 100644 index 000000000..c9bfd4f2e --- /dev/null +++ b/src/compaq.c @@ -0,0 +1,51 @@ +#include "ibm.h" +#include "mem.h" + +/* Compaq Deskpro 386 remaps RAM from 0xA0000-0xFFFFF to 0xFA0000-0xFFFFFF */ + +static mem_mapping_t compaq_ram_mapping; + +uint8_t compaq_read_ram(uint32_t addr, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} +uint16_t compaq_read_ramw(uint32_t addr, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} +uint32_t compaq_read_raml(uint32_t addr, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} +void compaq_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); +} +void compaq_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); +} +void compaq_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); +} + +void compaq_init() +{ + mem_mapping_add(&compaq_ram_mapping, 0xfa0000, 0x60000, + compaq_read_ram, compaq_read_ramw, compaq_read_raml, + compaq_write_ram, compaq_write_ramw, compaq_write_raml, + ram + 0xa0000, MEM_MAPPING_INTERNAL, NULL); +} diff --git a/src/compaq.h b/src/compaq.h new file mode 100644 index 000000000..36e9bc2ce --- /dev/null +++ b/src/compaq.h @@ -0,0 +1 @@ +void compaq_init(); diff --git a/src/config.c b/src/config.c new file mode 100644 index 000000000..676532563 --- /dev/null +++ b/src/config.c @@ -0,0 +1,400 @@ +#include +#include +#include +#include "config.h" + +char config_file_default[256]; + +static char config_file[256]; + +typedef struct list_t +{ + struct list_t *next; +} list_t; + +static list_t config_head; + +typedef struct section_t +{ + struct list_t list; + + char name[256]; + + struct list_t entry_head; +} section_t; + +typedef struct entry_t +{ + struct list_t list; + + char name[256]; + char data[256]; +} entry_t; + +#define list_add(new, head) \ + { \ + struct list_t *next = head; \ + \ + while (next->next) \ + next = next->next; \ + \ + (next)->next = new; \ + (new)->next = NULL; \ + } + +void config_dump() +{ + section_t *current_section; + + pclog("Config data :\n"); + + current_section = (section_t *)config_head.next; + + while (current_section) + { + entry_t *current_entry; + + pclog("[%s]\n", current_section->name); + + current_entry = (entry_t *)current_section->entry_head.next; + + while (current_entry) + { + pclog("%s = %s\n", current_entry->name, current_entry->data); + + current_entry = (entry_t *)current_entry->list.next; + } + + current_section = (section_t *)current_section->list.next; + } +} + +void config_free() +{ + section_t *current_section; + current_section = (section_t *)config_head.next; + + while (current_section) + { + section_t *next_section = (section_t *)current_section->list.next; + entry_t *current_entry; + + current_entry = (entry_t *)current_section->entry_head.next; + + while (current_entry) + { + entry_t *next_entry = (entry_t *)current_entry->list.next; + + free(current_entry); + current_entry = next_entry; + } + + free(current_section); + current_section = next_section; + } +} + +void config_load(char *fn) +{ + FILE *f = fopen(fn, "rt"); + section_t *current_section; + + memset(&config_head, 0, sizeof(list_t)); + + current_section = malloc(sizeof(section_t)); + memset(current_section, 0, sizeof(section_t)); + list_add(¤t_section->list, &config_head); + + if (!f) + return; + + while (1) + { + int c; + char buffer[256]; + + fgets(buffer, 255, f); + if (feof(f)) break; + + c = 0; + + while (buffer[c] == ' ' && buffer[c]) + c++; + + if (!buffer[c]) continue; + + if (buffer[c] == '#') /*Comment*/ + continue; + + if (buffer[c] == '[') /*Section*/ + { + section_t *new_section; + char name[256]; + int d = 0; + + c++; + while (buffer[c] != ']' && buffer[c]) + name[d++] = buffer[c++]; + + if (buffer[c] != ']') + continue; + name[d] = 0; + + new_section = malloc(sizeof(section_t)); + memset(new_section, 0, sizeof(section_t)); + strncpy(new_section->name, name, 256); + list_add(&new_section->list, &config_head); + + current_section = new_section; + +// pclog("New section : %s %p\n", name, (void *)current_section); + } + else + { + entry_t *new_entry; + char name[256]; + int d = 0, data_pos; + + while (buffer[c] != '=' && buffer[c] != ' ' && buffer[c]) + name[d++] = buffer[c++]; + + if (!buffer[c]) continue; + name[d] = 0; + + while ((buffer[c] == '=' || buffer[c] == ' ') && buffer[c]) + c++; + + if (!buffer[c]) continue; + + data_pos = c; + while (buffer[c]) + { + if (buffer[c] == '\n') + buffer[c] = 0; + c++; + } + + new_entry = malloc(sizeof(entry_t)); + memset(new_entry, 0, sizeof(entry_t)); + strncpy(new_entry->name, name, 256); + strncpy(new_entry->data, &buffer[data_pos], 256); + list_add(&new_entry->list, ¤t_section->entry_head); + +// pclog("New data under section [%s] : %s = %s\n", current_section->name, new_entry->name, new_entry->data); + } + } + + fclose(f); + + config_dump(); +} + + + +void config_new() +{ + FILE *f = fopen(config_file, "wt"); + fclose(f); +} + +static section_t *find_section(char *name) +{ + section_t *current_section; + char blank[] = ""; + + current_section = (section_t *)config_head.next; + if (!name) + name = blank; + + while (current_section) + { + if (!strncmp(current_section->name, name, 256)) + return current_section; + + current_section = (section_t *)current_section->list.next; + } + return NULL; +} + +static entry_t *find_entry(section_t *section, char *name) +{ + entry_t *current_entry; + + current_entry = (entry_t *)section->entry_head.next; + + while (current_entry) + { + if (!strncmp(current_entry->name, name, 256)) + return current_entry; + + current_entry = (entry_t *)current_entry->list.next; + } + return NULL; +} + +static section_t *create_section(char *name) +{ + section_t *new_section = malloc(sizeof(section_t)); + + memset(new_section, 0, sizeof(section_t)); + strncpy(new_section->name, name, 256); + list_add(&new_section->list, &config_head); + + return new_section; +} + +static entry_t *create_entry(section_t *section, char *name) +{ + entry_t *new_entry = malloc(sizeof(entry_t)); + memset(new_entry, 0, sizeof(entry_t)); + strncpy(new_entry->name, name, 256); + list_add(&new_entry->list, §ion->entry_head); + + return new_entry; +} + +int config_get_int(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + + if (!section) + return def; + + entry = find_entry(section, name); + + if (!entry) + return def; + + sscanf(entry->data, "%i", &value); + + return value; +} + +char *config_get_string(char *head, char *name, char *def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + + if (!section) + return def; + + entry = find_entry(section, name); + + if (!entry) + return def; + + return entry->data; +} + +void config_set_int(char *head, char *name, int val) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + section = create_section(head); + + entry = find_entry(section, name); + + if (!entry) + entry = create_entry(section, name); + + sprintf(entry->data, "%i", val); +} + +void config_set_string(char *head, char *name, char *val) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + section = create_section(head); + + entry = find_entry(section, name); + + if (!entry) + entry = create_entry(section, name); + + strncpy(entry->data, val, 256); +} + + +char *get_filename(char *s) +{ + int c = strlen(s) - 1; + while (c > 0) + { + if (s[c] == '/' || s[c] == '\\') + return &s[c+1]; + c--; + } + return s; +} + +void append_filename(char *dest, char *s1, char *s2, int size) +{ + sprintf(dest, "%s%s", s1, s2); +} + +void put_backslash(char *s) +{ + int c = strlen(s) - 1; + if (s[c] != '/' && s[c] != '\\') + s[c] = '/'; +} + +char *get_extension(char *s) +{ + int c = strlen(s) - 1; + + if (c <= 0) + return s; + + while (c && s[c] != '.') + c--; + + if (!c) + return &s[strlen(s)]; + + return &s[c+1]; +} + +void config_save(char *fn) +{ + FILE *f = fopen(fn, "wt"); + section_t *current_section; + + current_section = (section_t *)config_head.next; + + while (current_section) + { + entry_t *current_entry; + + if (current_section->name[0]) + fprintf(f, "\n[%s]\n", current_section->name); + + current_entry = (entry_t *)current_section->entry_head.next; + + while (current_entry) + { + fprintf(f, "%s = %s\n", current_entry->name, current_entry->data); + + current_entry = (entry_t *)current_entry->list.next; + } + + current_section = (section_t *)current_section->list.next; + } + + fclose(f); +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 000000000..5c4f4e495 --- /dev/null +++ b/src/config.h @@ -0,0 +1,16 @@ +int config_get_int(char *head, char *name, int def); +char *config_get_string(char *head, char *name, char *def); +void config_set_int(char *head, char *name, int val); +void config_set_string(char *head, char *name, char *val); + +char *get_filename(char *s); +void append_filename(char *dest, char *s1, char *s2, int size); +void put_backslash(char *s); +char *get_extension(char *s); + +void config_load(char *fn); +void config_save(char *fn); +void config_dump(); +void config_free(); + +extern char config_file_default[256]; diff --git a/src/cpu.c b/src/cpu.c new file mode 100644 index 000000000..5fc2d6fe5 --- /dev/null +++ b/src/cpu.c @@ -0,0 +1,2260 @@ +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "io.h" +#include "x86_ops.h" +#include "mem.h" +#include "pci.h" +#include "codegen.h" + +int isa_cycles; +static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; + +OpFn *x86_dynarec_opcodes; +OpFn *x86_dynarec_opcodes_0f; +OpFn *x86_dynarec_opcodes_d8_a16; +OpFn *x86_dynarec_opcodes_d8_a32; +OpFn *x86_dynarec_opcodes_d9_a16; +OpFn *x86_dynarec_opcodes_d9_a32; +OpFn *x86_dynarec_opcodes_da_a16; +OpFn *x86_dynarec_opcodes_da_a32; +OpFn *x86_dynarec_opcodes_db_a16; +OpFn *x86_dynarec_opcodes_db_a32; +OpFn *x86_dynarec_opcodes_dc_a16; +OpFn *x86_dynarec_opcodes_dc_a32; +OpFn *x86_dynarec_opcodes_dd_a16; +OpFn *x86_dynarec_opcodes_dd_a32; +OpFn *x86_dynarec_opcodes_de_a16; +OpFn *x86_dynarec_opcodes_de_a32; +OpFn *x86_dynarec_opcodes_df_a16; +OpFn *x86_dynarec_opcodes_df_a32; + +OpFn *x86_opcodes; +OpFn *x86_opcodes_0f; +OpFn *x86_opcodes_d8_a16; +OpFn *x86_opcodes_d8_a32; +OpFn *x86_opcodes_d9_a16; +OpFn *x86_opcodes_d9_a32; +OpFn *x86_opcodes_da_a16; +OpFn *x86_opcodes_da_a32; +OpFn *x86_opcodes_db_a16; +OpFn *x86_opcodes_db_a32; +OpFn *x86_opcodes_dc_a16; +OpFn *x86_opcodes_dc_a32; +OpFn *x86_opcodes_dd_a16; +OpFn *x86_opcodes_dd_a32; +OpFn *x86_opcodes_de_a16; +OpFn *x86_opcodes_de_a32; +OpFn *x86_opcodes_df_a16; +OpFn *x86_opcodes_df_a32; + +enum +{ + CPUID_FPU = (1 << 0), + CPUID_TSC = (1 << 4), + CPUID_MSR = (1 << 5), + CPUID_CMPXCHG8B = (1 << 8), + CPUID_AMDSEP = (1 << 10), + CPUID_SEP = (1 << 11), + CPUID_CMOV = (1 << 15), + CPUID_MMX = (1 << 23), + CPUID_FXSR = (1 << 24) +}; + +int cpu = 3, cpu_manufacturer = 0; +CPU *cpu_s; +int cpu_multi; +int cpu_iscyrix; +int cpu_16bitbus; +int cpu_busspeed; +int cpu_hasrdtsc; +int cpu_hasMMX, cpu_hasMSR; +int cpu_hasCR4; +int cpu_use_dynarec; + +uint64_t cpu_CR4_mask; + +int is286, is386; + +uint64_t tsc = 0; + +uint64_t pmc[2] = {0, 0}; + +uint16_t temp_seg_data[4] = {0, 0, 0, 0}; + +uint16_t cs_msr = 0; +uint32_t esp_msr = 0; +uint32_t eip_msr = 0; +uint64_t apic_base_msr = 0; +uint64_t mtrr_cap_msr = 0; +uint64_t mtrr_physbase_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_physmask_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_fix64k_8000_msr = 0; +uint64_t mtrr_fix16k_8000_msr = 0; +uint64_t mtrr_fix16k_a000_msr = 0; +uint64_t mtrr_fix4k_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t pat_msr = 0; +uint64_t mtrr_deftype_msr = 0; +uint64_t ecx17_msr = 0; +uint64_t ecx79_msr = 0; +uint64_t ecx8x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx116_msr = 0; +uint64_t ecx11x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx11e_msr = 0; +uint64_t ecx1e0_msr = 0; + +/* AMD K5 and K6 MSR's. */ +uint64_t ecx83_msr = 0; +/* These are K6-only. */ +uint64_t star = 0; +uint64_t sfmask = 0; + +int timing_rr; +int timing_mr, timing_mrl; +int timing_rm, timing_rml; +int timing_mm, timing_mml; +int timing_bt, timing_bnt; +int timing_int, timing_int_rm, timing_int_v86, timing_int_pm, timing_int_pm_outer; +int timing_iret_rm, timing_iret_v86, timing_iret_pm, timing_iret_pm_outer; +int timing_call_rm, timing_call_pm, timing_call_pm_gate, timing_call_pm_gate_inner; +int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; + +static struct +{ + uint32_t tr1, tr12; + uint32_t cesr; + uint32_t fcr; + uint64_t fcr2, fcr3; +} msr; + +/*Available cpuspeeds : + 0 = 16 MHz + 1 = 20 MHz + 2 = 25 MHz + 3 = 33 MHz + 4 = 40 MHz + 5 = 50 MHz + 6 = 66 MHz + 7 = 75 MHz + 8 = 80 MHz + 9 = 90 MHz + 10 = 100 MHz + 11 = 120 MHz + 12 = 133 MHz + 13 = 150 MHz + 14 = 160 MHz + 15 = 166 MHz + 16 = 180 MHz + 17 = 200 MHz +*/ + +CPU cpus_8088[] = +{ + /*8088 standard*/ + {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0}, + {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0}, + {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0}, + {"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0, 0, 0}, + {"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0, 0, 0}, + {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_pcjr[] = +{ + /*8088 PCjr*/ + {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_8086[] = +{ + /*8086 standard*/ + {"8086/7.16", CPU_8086, 1, 14318184/2, 1, 0, 0, 0, 0, 0}, + {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0}, + {"8086/9.54", CPU_8086, 1, 4772728*2, 1, 0, 0, 0, 0, 0}, + {"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0, 0, 0}, + {"8086/12", CPU_8086, 3, 12000000, 1, 0, 0, 0, 0, 0}, + {"8086/16", CPU_8086, 4, 16000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_pc1512[] = +{ + /*8086 Amstrad*/ + {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_286[] = +{ + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0}, + {"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0, 0, 0}, + {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0}, + {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0}, + {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0}, + {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0}, + {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_ibmat[] = +{ + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0}, + {"286/8", CPU_286, 0, 8000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_ps1_m2011[] = +{ + /*286*/ + {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_i386[] = +{ + /*i386*/ + {"i386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0}, + {"i386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0}, + {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0}, + {"i386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0}, + {"i386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0}, + {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0, 0x0308, 0, 0, 0}, + {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0, 0x0308, 0, 0, 0}, + {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0}, + {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0}, + {"i386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0}, + {"RapidCAD/25", CPU_i486DX, 2, 25000000, 1, 0, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"RapidCAD/33", CPU_i486DX, 3, 33333333, 1, 0, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"RapidCAD/40", CPU_i486DX, 4, 40000000, 1, 0, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_acer[] = +{ + /*i386*/ + {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Am386[] = +{ + /*Am386*/ + {"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0}, + {"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0}, + {"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0}, + {"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0}, + {"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0}, + {"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0}, + {"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0}, + {"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_486SDLC[] = +{ + /*Cx486SLC/DLC*/ + {"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0, 0, 0x0000, 0}, + {"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0, 0, 0x0000, 0}, + {"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0, 0, 0x0000, 0}, + {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0, 0, 0x0006, 0}, + {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0, 0, 0x0006, 0}, + {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0, 0, 0x0006, 0}, + {"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0, 0, 0x0001, 0}, + {"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0, 0, 0x0001, 0}, + {"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0, 0, 0x0001, 0}, + {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0, 0, 0x0007, 0}, + {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0, 0, 0x0007, 0}, + {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0, 0, 0x0007, 0}, + {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0, 0, 0x0007, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_i486[] = +{ + /*i486*/ + {"i486SX/16", CPU_i486SX, 0, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486SX/20", CPU_i486SX, 1, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486SX/25", CPU_i486SX, 2, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486SX/33", CPU_i486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX/25", CPU_i486DX, 2, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX/33", CPU_i486DX, 3, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX/50", CPU_i486DX, 5, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"iDX4/75", CPU_i486DX, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC}, /*CPUID available on DX4, >= 75 MHz*/ + {"iDX4/100", CPU_i486DX,10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ + {"Pentium OverDrive/63", CPU_PENTIUM, 6, 62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive/83", CPU_PENTIUM, 8, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Am486[] = +{ + /*Am486/5x86*/ + {"Am486SX/33", CPU_Am486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ + {"Am486SX2/66", CPU_Am486SX, 6, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/ + {"Am486DX/33", CPU_Am486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC}, + {"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am5x86/P75+", CPU_Am486DX, 13, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Cx486[] = +{ + /*Cx486/5x86*/ + {"Cx486S/25", CPU_Cx486S, 2, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC}, + {"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC}, + {"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC}, + {"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC}, + {"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC}, + {"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC}, + {"", -1, 0, 0, 0} +}; + + CPU cpus_6x86[] = + { + /*Cyrix 6x86*/ + {"6x86-P90", CPU_Cx6x86, 17, 80000000, 3, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR120+", CPU_Cx6x86, 17, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR133+", CPU_Cx6x86, 17, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR150+", CPU_Cx6x86, 17, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR166+", CPU_Cx6x86, 17, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR200+", CPU_Cx6x86, 17, 150000000, 3, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + + /*Cyrix 6x86L*/ + {"6x86L-PR133+", CPU_Cx6x86L, 19, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86L-PR150+", CPU_Cx6x86L, 19, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86L-PR166+", CPU_Cx6x86L, 19, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86L-PR200+", CPU_Cx6x86L, 19, 150000000, 3, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + + /*Cyrix 6x86MX*/ + {"6x86MX-PR90/75",CPU_Cx6x86MX, 18, 75000000, 2, 25000000, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR90", CPU_Cx6x86MX, 18, 90000000, 2, 30000000, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR133", CPU_Cx6x86MX, 18, 100000000, 2, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR150", CPU_Cx6x86MX, 18, 120000000, 3, 30000000, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR166", CPU_Cx6x86MX, 18, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR200", CPU_Cx6x86MX, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR233", CPU_Cx6x86MX, 18, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR266", CPU_Cx6x86MX, 18, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR300", CPU_Cx6x86MX, 18, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR333", CPU_Cx6x86MX, 18, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR366", CPU_Cx6x86MX, 18, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR400", CPU_Cx6x86MX, 18, 285000000, 3, 31666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} + }; + + + +CPU cpus_WinChip[] = +{ + /*IDT WinChip*/ + {"WinChip 75", CPU_WINCHIP, 7, 75000000, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 90", CPU_WINCHIP, 9, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 100", CPU_WINCHIP, 10, 100000000, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 120", CPU_WINCHIP, 11, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 133", CPU_WINCHIP, 12, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 150", CPU_WINCHIP, 13, 150000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 166", CPU_WINCHIP, 15, 166666666, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 180", CPU_WINCHIP, 16, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 200", CPU_WINCHIP, 17, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 225", CPU_WINCHIP, 17, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 240", CPU_WINCHIP, 17, 240000000, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium5V[] = +{ + /*Intel Pentium (5V, socket 4)*/ + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium5V50[] = +{ + /*Intel Pentium (5V, socket 4, including 50 MHz FSB)*/ + {"Pentium 50 (Q0399)",CPU_PENTIUM, 5, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 100",CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_PentiumS5[] = +{ + /*Intel Pentium (Socket 5)*/ + {"Pentium 50 (Q0399)",CPU_PENTIUM, 5, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 50", CPU_PENTIUMMMX, 5, 50000000, 1, 25000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 60", CPU_PENTIUMMMX, 6, 60000000, 1, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 66", CPU_PENTIUMMMX, 6, 66666666, 1, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 75", CPU_PENTIUMMMX, 9, 75000000, 2, 25000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 90", CPU_PENTIUMMMX, 12, 90000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium[] = +{ + /*Intel Pentium*/ + {"Pentium 50 (Q0399)",CPU_PENTIUM, 5, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 50", CPU_PENTIUMMMX, 5, 50000000, 1, 25000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 60", CPU_PENTIUMMMX, 6, 60000000, 1, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 66", CPU_PENTIUMMMX, 6, 66666666, 1, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 75", CPU_PENTIUMMMX, 9, 75000000, 2, 25000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 90", CPU_PENTIUMMMX, 12, 90000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 133", CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 150", CPU_PENTIUM, 17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 166", CPU_PENTIUM, 19, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 200", CPU_PENTIUM, 21, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, 14, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, 16, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, 17, 150000000, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, 26, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, 28, 300000000, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_K5[] = +{ + /*AMD K5 (Socket 5)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 1.50, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 1.50, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 1.50, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 1.50, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 1.50, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 1.50, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2.00, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2.00, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 2.50, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 2.50, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3.00, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_K56[] = +{ + /*AMD K5 and K6 (Socket 7)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 1.50, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 1.50, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 1.50, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 1.50, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 1.50, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 1.50, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2.00, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2.00, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 2.50, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 2.50, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3.00, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 6) 166", CPU_K6, 19, 166666666, 2.50, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 6) 200", CPU_K6, 21, 200000000, 3.00, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 6) 233", CPU_K6, 24, 233333333, 3.50, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 7) 200", CPU_K6, 21, 200000000, 3.00, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 7) 233", CPU_K6, 24, 233333333, 3.50, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 7) 266", CPU_K6, 26, 266666666, 4.00, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 7) 300", CPU_K6, 28, 300000000, 4.50, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_PentiumPro[] = +{ + /*Intel Pentium Pro and II Overdrive*/ + {"Pentium Pro 150", CPU_PENTIUMPRO, 17, 150000000, 2.50, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium Pro 166", CPU_PENTIUMPRO, 19, 166666666, 2.50, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium Pro 180", CPU_PENTIUMPRO, 20, 180000000, 3.00, 30000000, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium Pro 200", CPU_PENTIUMPRO, 21, 200000000, 3.00, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 210", CPU_PENTIUM2D, 22, 210000000, 3.50, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 233", CPU_PENTIUM2D, 24, 233333333, 3.50, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 240", CPU_PENTIUM2D, 25, 240000000, 4.00, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 266", CPU_PENTIUM2D, 26, 266666666, 4.00, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 270", CPU_PENTIUM2D, 27, 270000000, 4.50, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 300/66",CPU_PENTIUM2D, 28, 300000000, 4.50, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 300/60",CPU_PENTIUM2D, 28, 300000000, 5.00, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 333", CPU_PENTIUM2D, 29, 333333333, 5.00, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium2[] = +{ + /*Intel Pentium II Klamath*/ + {"Pentium II 233", CPU_PENTIUM2, 24, 233333333, 3.50, 33333333, 0x632, 0x632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II 266", CPU_PENTIUM2, 26, 266666666, 4.00, 33333333, 0x633, 0x633, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II 300", CPU_PENTIUM2, 28, 300000000, 4.50, 33333333, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium2D[] = +{ + /*Intel Pentium II Deschutes*/ + {"Pentium II D 266", CPU_PENTIUM2D, 26, 266666666, 4.00, 33333333, 0x650, 0x650, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 300", CPU_PENTIUM2D, 28, 300000000, 4.50, 33333333, 0x650, 0x650, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 333", CPU_PENTIUM2D, 29, 333333333, 5.00, 33333333, 0x650, 0x650, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 350", CPU_PENTIUM2D, 30, 350000000, 3.50, 50000000, 0x653, 0x653, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 400", CPU_PENTIUM2D, 31, 400000000, 4.00, 50000000, 0x653, 0x653, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 450", CPU_PENTIUM2D, 32, 450000000, 4.50, 50000000, 0x654, 0x654, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 500", CPU_PENTIUM2D, 33, 500000000, 5.00, 50000000, 0x654, 0x654, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +void cpu_set_edx() +{ + EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset; +} + +void cpu_set() +{ + CPU *cpu_s; + + if (!models[model].cpu[cpu_manufacturer].cpus) + { + /*CPU is invalid, set to default*/ + cpu_manufacturer = 0; + cpu = 0; + } + + cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu]; + + CPUID = cpu_s->cpuid_model; + cpuspeed = cpu_s->speed; + is8086 = (cpu_s->cpu_type > CPU_8088); + is286 = (cpu_s->cpu_type >= CPU_286); + is386 = (cpu_s->cpu_type >= CPU_386SX); + is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC); + hasfpu = (cpu_s->cpu_type >= CPU_i486DX); + cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86 || cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86MX || cpu_s->cpu_type == CPU_Cx6x86L || cpu_s->cpu_type == CPU_CxGX1); + cpu_16bitbus = (cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC); + if (cpu_s->multi) + cpu_busspeed = cpu_s->rspeed / cpu_s->multi; + cpu_multi = cpu_s->multi; + cpu_hasrdtsc = 0; + cpu_hasMMX = 0; + cpu_hasMSR = 0; + cpu_hasCR4 = 0; + ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; + + isa_cycles = (int)(((int64_t)cpu_s->rspeed << ISA_CYCLES_SHIFT) / 8000000ll); + + if (cpu_s->pci_speed) + { + pci_nonburst_time = 3*cpu_s->rspeed / cpu_s->pci_speed; + pci_burst_time = cpu_s->rspeed / cpu_s->pci_speed; + } + else + { + pci_nonburst_time = 3; + pci_burst_time = 1; + } + pclog("PCI burst=%i nonburst=%i\n", pci_burst_time, pci_nonburst_time); + + if (cpu_iscyrix) + io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); + else + io_removehandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); + + pclog("hasfpu - %i\n",hasfpu); + pclog("is486 - %i %i\n",is486,cpu_s->cpu_type); + + x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); + + if (hasfpu) + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_fpu_d8_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_fpu_d8_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_df_a32; + } + else + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_nofpu_a32; + } + codegen_timing_set(&codegen_timing_486); + + if (hasfpu) + { + x86_opcodes_d8_a16 = ops_fpu_d8_a16; + x86_opcodes_d8_a32 = ops_fpu_d8_a32; + x86_opcodes_d9_a16 = ops_fpu_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_d9_a32; + x86_opcodes_da_a16 = ops_fpu_da_a16; + x86_opcodes_da_a32 = ops_fpu_da_a32; + x86_opcodes_db_a16 = ops_fpu_db_a16; + x86_opcodes_db_a32 = ops_fpu_db_a32; + x86_opcodes_dc_a16 = ops_fpu_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_dd_a32; + x86_opcodes_de_a16 = ops_fpu_de_a16; + x86_opcodes_de_a32 = ops_fpu_de_a32; + x86_opcodes_df_a16 = ops_fpu_df_a16; + x86_opcodes_df_a32 = ops_fpu_df_a32; + } + else + { + x86_opcodes_d8_a16 = ops_nofpu_a16; + x86_opcodes_d8_a32 = ops_nofpu_a32; + x86_opcodes_d9_a16 = ops_nofpu_a16; + x86_opcodes_d9_a32 = ops_nofpu_a32; + x86_opcodes_da_a16 = ops_nofpu_a16; + x86_opcodes_da_a32 = ops_nofpu_a32; + x86_opcodes_db_a16 = ops_nofpu_a16; + x86_opcodes_db_a32 = ops_nofpu_a32; + x86_opcodes_dc_a16 = ops_nofpu_a16; + x86_opcodes_dc_a32 = ops_nofpu_a32; + x86_opcodes_dd_a16 = ops_nofpu_a16; + x86_opcodes_dd_a32 = ops_nofpu_a32; + x86_opcodes_de_a16 = ops_nofpu_a16; + x86_opcodes_de_a32 = ops_nofpu_a32; + x86_opcodes_df_a16 = ops_nofpu_a16; + x86_opcodes_df_a32 = ops_nofpu_a32; + } + + memset(&msr, 0, sizeof(msr)); + + switch (cpu_s->cpu_type) + { + case CPU_8088: + case CPU_8086: + break; + + case CPU_286: + x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f); + timing_rr = 2; /*register dest - register src*/ + timing_rm = 7; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 7; /*memory dest - memory src*/ + timing_rml = 9; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 11; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 23; + timing_int_v86 = 0; + timing_int_pm = 40; + timing_int_pm_outer = 78; + timing_iret_rm = 17; + timing_iret_v86 = 0; + timing_iret_pm = 31; + timing_iret_pm_outer = 55; + timing_call_rm = 13; + timing_call_pm = 26; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 82; + timing_retf_rm = 15; + timing_retf_pm = 25; + timing_retf_pm_outer = 55; + timing_jmp_rm = 11; + timing_jmp_pm = 23; + timing_jmp_pm_gate = 38; + break; + + case CPU_386SX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 8; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 10; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_386DX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 6; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 6; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_486SLC: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 5; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 5; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 7; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + break; + + case CPU_486DLC: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + break; + + case CPU_i486SX: + case CPU_i486DX: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + break; + + case CPU_Am486SX: + case CPU_Am486DX: + /*AMD timing identical to Intel*/ + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + break; + + case CPU_Cx486S: + case CPU_Cx486DX: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 4-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; /*unknown*/ + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + break; + + case CPU_Cx5x86: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 9; + timing_int_v86 = 82; /*unknown*/ + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + break; + + case CPU_WINCHIP: + x86_setopcodes(ops_386, ops_winchip_0f, dynarec_ops_386, dynarec_ops_winchip_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + /*unknown*/ + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + codegen_timing_set(&codegen_timing_winchip); + break; + + case CPU_PENTIUM: + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_pentium); + break; + + case CPU_PENTIUMMMX: + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_pentium); + break; + + case CPU_Cx6x86: + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 0; + cpu_hasCR4 = 0; + codegen_timing_set(&codegen_timing_686); + CPUID = 0; /*Disabled on powerup by default*/ + break; + + case CPU_Cx6x86L: + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 0; + cpu_hasCR4 = 0; + codegen_timing_set(&codegen_timing_686); + ccr4 = 0x80; + break; + + + case CPU_CxGX1: + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; + codegen_timing_set(&codegen_timing_686); + break; + + + case CPU_Cx6x86MX: + x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; + codegen_timing_set(&codegen_timing_686); + ccr4 = 0x80; + break; + + case CPU_K5: + case CPU_5K86: + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + break; + + case CPU_K6: + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_pentium); + break; + + case CPU_PENTIUMPRO: + x86_setopcodes(ops_386, ops_pentiumpro_0f, dynarec_ops_386, dynarec_ops_pentiumpro_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_686); + break; + + case CPU_PENTIUM2: + x86_setopcodes(ops_386, ops_pentium2_0f, dynarec_ops_386, dynarec_ops_pentium2_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_686); + break; + + case CPU_PENTIUM2D: + x86_setopcodes(ops_386, ops_pentium2d_0f, dynarec_ops_386, dynarec_ops_pentium2d_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE | CR4_OSFXSR; + codegen_timing_set(&codegen_timing_686); + break; + + default: + fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type); + } +} + +void cpu_CPUID() +{ + switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) + { + case CPU_i486DX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = 0; + break; + + case CPU_Am486SX: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = EDX = 0; /*No FPU*/ + } + else + EAX = 0; + break; + + case CPU_Am486DX: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = 0; + break; + + case CPU_WINCHIP: + if (!EAX) + { + EAX = 1; + if (msr.fcr2 & (1 << 14)) + { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } + else + { + EBX = 0x746e6543; /*CentaurHauls*/ + ECX = 0x736c7561; + EDX = 0x48727561; + } + } + else if (EAX == 1) + { + EAX = 0x540; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + } + else + EAX = 0; + break; + + case CPU_PENTIUM: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = 0; + break; + + case CPU_K5: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = 0; + break; + + case CPU_5K86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x7428354B; + ECX = 0x5020296D; + EDX = 0x65636F72; + } + else if (EAX == 0x80000003) + { + EAX = 0x726F7373; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000004) + { + EAX = EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x04800000; + ECX = 0x08040120; + EDX = 0x10040120; + } + else + EAX = 0; + break; + + case CPU_K6: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID + 0x100; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x6D74364B; + ECX = 0x202F7720; + EDX = 0x746C756D; + } + else if (EAX == 0x80000003) + { + EAX = 0x64656D69; + EBX = 0x65206169; + ECX = 0x6E657478; + EDX = 0x6E6F6973; + } + else if (EAX == 0x80000004) + { + EAX = 0x73; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x02800140; + ECX = 0x20020220; + EDX = 0x20020220; + } + else if (EAX == 0x8FFFFFFF) + { + EAX = 0x4778654E; + EBX = 0x72656E65; + ECX = 0x6F697461; + EDX = 0x444D416E; + } + else + EAX = 0; + break; + + case CPU_PENTIUMMMX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + } + else + EAX = 0; + break; + + + case CPU_Cx6x86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; + } + else + EAX = 0; + break; + + + case CPU_Cx6x86L: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_CMPXCHG8B; + } + else + EAX = 0; + break; + + + case CPU_CxGX1: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = 0; + break; + + + + case CPU_Cx6x86MX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; + } + else + EAX = 0; + break; + + case CPU_PENTIUMPRO: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_SEP | CPUID_CMOV; + } + else if (EAX == 2) + { + } + else + EAX = 0; + break; + + case CPU_PENTIUM2: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_CMOV; + // EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_CMOV; + // EDX = 0x0183FBFF; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040843; + } + else + EAX = 0; + break; + + case CPU_PENTIUM2D: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_FXSR | CPUID_CMOV; + // EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_FXSR | CPUID_CMOV; + // EDX = 0x0183FBFF; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040844; + } + else + EAX = 0; + break; + + } +} + +void cpu_RDMSR() +{ + switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) + { + case CPU_WINCHIP: + EAX = EDX = 0; + switch (ECX) + { + case 0x02: + EAX = msr.tr1; + break; + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x11: + EAX = msr.cesr; + break; + case 0x107: + EAX = msr.fcr; + break; + case 0x108: + EAX = msr.fcr2 & 0xffffffff; + EDX = msr.fcr2 >> 32; + break; + case 0x10a: + EAX = cpu_multi & 3; + break; + } + break; + + case CPU_K5: + case CPU_5K86: + case CPU_K6: + EAX = EDX = 0; + switch (ECX) + { + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x83: + EAX = ecx83_msr & 0xffffffff; + EDX = ecx83_msr >> 32; + break; + case 0xC0000081: + EAX = star & 0xffffffff; + EDX = star >> 32; + break; + case 0xC0000084: + EAX = sfmask & 0xffffffff; + EDX = sfmask >> 32; + break; + default: +#ifndef RELEASE_BUILD + pclog("Invalid MSR: %08X\n", ECX); +#endif + x86gpf(NULL, 0); + break; + } + break; + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + + case CPU_PENTIUMPRO: + case CPU_PENTIUM2: + case CPU_PENTIUM2D: + EAX = EDX = 0; + // pclog("RDMSR, ECX=%08X\n", ECX); + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x17: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type != CPU_PENTIUM2D) goto i686_invalid_rdmsr; + EAX = ecx17_msr & 0xffffffff; + EDX = ecx17_msr >> 32; + break; + case 0x1B: + EAX = apic_base_msr & 0xffffffff; + EDX = apic_base_msr >> 32; + break; + case 0x2A: + EAX = 0xC5800000; + EDX = 0; + break; + case 0x79: + EAX = ecx79_msr & 0xffffffff; + EDX = ecx79_msr >> 32; + break; + case 0x88 ... 0x8B: + EAX = ecx8x_msr[ECX - 0x88] & 0xffffffff; + EDX = ecx8x_msr[ECX - 0x88] >> 32; + break; + case 0xFE: + EAX = mtrr_cap_msr & 0xffffffff; + EDX = mtrr_cap_msr >> 32; + break; + case 0x116: + EAX = ecx116_msr & 0xffffffff; + EDX = ecx116_msr >> 32; + break; + case 0x118 ... 0x11B: + EAX = ecx11x_msr[ECX - 0x118] & 0xffffffff; + EDX = ecx11x_msr[ECX - 0x118] >> 32; + break; + case 0x11E: + EAX = ecx11e_msr & 0xffffffff; + EDX = ecx11e_msr >> 32; + break; + case 0x174: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX &= 0xFFFF0000; + EAX |= cs_msr; + break; + case 0x175: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = esp_msr; + break; + case 0x176: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = eip_msr; + break; + case 0x1E0: + EAX = ecx1e0_msr & 0xffffffff; + EDX = ecx1e0_msr >> 32; + break; + case 0x200 ... 0x20F: + if (ECX & 1) + { + EAX = mtrr_physmask_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physmask_msr[(ECX - 0x200) >> 1] >> 32; + } + else + { + EAX = mtrr_physbase_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physbase_msr[(ECX - 0x200) >> 1] >> 32; + } + break; + case 0x250: + EAX = mtrr_fix64k_8000_msr & 0xffffffff; + EDX = mtrr_fix64k_8000_msr >> 32; + break; + case 0x258: + EAX = mtrr_fix16k_8000_msr & 0xffffffff; + EDX = mtrr_fix16k_8000_msr >> 32; + break; + case 0x259: + EAX = mtrr_fix16k_a000_msr & 0xffffffff; + EDX = mtrr_fix16k_a000_msr >> 32; + break; + case 0x268 ... 0x26F: + // ((ECX - 0x268) * 0x8000) + EAX = mtrr_fix4k_msr[ECX - 0x268] & 0xffffffff; + EDX = mtrr_fix4k_msr[ECX - 0x268] >> 32; + break; + case 0x277: + EAX = pat_msr & 0xffffffff; + EDX = pat_msr >> 32; + break; + case 0x2FF: + EAX = mtrr_deftype_msr & 0xffffffff; + EDX = mtrr_deftype_msr >> 32; + break; + default: +i686_invalid_rdmsr: +#ifndef RELEASE_BUILD + pclog("Invalid MSR: %08X\n", ECX); +#endif + x86gpf(NULL, 0); + break; + } + break; + } +} + +void cpu_WRMSR() +{ + switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) + { + case CPU_WINCHIP: + switch (ECX) + { + case 0x02: + msr.tr1 = EAX & 2; + break; + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x11: + msr.cesr = EAX & 0xff00ff; + break; + case 0x107: + msr.fcr = EAX; + cpu_hasMMX = EAX & (1 << 9); + if (EAX & (1 << 29)) + CPUID = 0; + else + CPUID = models[model].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; + break; + case 0x108: + msr.fcr2 = EAX | ((uint64_t)EDX << 32); + break; + case 0x109: + msr.fcr3 = EAX | ((uint64_t)EDX << 32); + break; + } + break; + case CPU_K5: + case CPU_5K86: + case CPU_K6: + switch (ECX) + { + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x83: + ecx83_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000081: + star = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000084: + sfmask = EAX | ((uint64_t)EDX << 32); + break; + } + break; + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + + case CPU_PENTIUMPRO: + case CPU_PENTIUM2: + case CPU_PENTIUM2D: + // pclog("WRMSR, ECX=%08X\n", ECX); + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x17: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type != CPU_PENTIUM2D) goto i686_invalid_wrmsr; + ecx17_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x1B: + apic_base_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x79: + ecx79_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x88 ... 0x8B: + ecx8x_msr[ECX - 0x88] = EAX | ((uint64_t)EDX << 32); + break; + case 0xFE: + mtrr_cap_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x116: + ecx116_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x118 ... 0x011B: + ecx11x_msr[ECX - 0x118] = EAX | ((uint64_t)EDX << 32); + break; + case 0x11E: + ecx11e_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x174: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + // pclog("WRMSR SYSENTER_CS: old=%04X, new=%04X\n", cs_msr, (uint16_t) (EAX & 0xFFFF)); + cs_msr = EAX & 0xFFFF; + break; + case 0x175: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + // pclog("WRMSR SYSENTER_ESP: old=%08X, new=%08X\n", esp_msr, EAX); + esp_msr = EAX; + break; + case 0x176: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + // pclog("WRMSR SYSENTER_EIP: old=%08X, new=%08X\n", eip_msr, EAX); + eip_msr = EAX; + break; + case 0x1E0: + ecx1e0_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x200 ... 0x20F: + if (ECX & 1) + mtrr_physmask_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + else + mtrr_physbase_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + break; + case 0x250: + mtrr_fix64k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x258: + mtrr_fix16k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x259: + mtrr_fix16k_a000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x268 ... 0x26F: + // ((ECX - 0x268) * 0x8000) + mtrr_fix4k_msr[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); + break; + case 0x277: + pat_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x2FF: + mtrr_deftype_msr = EAX | ((uint64_t)EDX << 32); + break; + default: +i686_invalid_wrmsr: +#ifndef RELEASE_BUILD + pclog("Invalid MSR: %08X\n", ECX); +#endif + x86gpf(NULL, 0); + break; + } + break; + } +} + +static int cyrix_addr; + +void cyrix_write(uint16_t addr, uint8_t val, void *priv) +{ + if (!(addr & 1)) + cyrix_addr = val; + else switch (cyrix_addr) + { + case 0xc0: /*CCR0*/ + ccr0 = val; + break; + case 0xc1: /*CCR1*/ + ccr1 = val; + break; + case 0xc2: /*CCR2*/ + ccr2 = val; + break; + case 0xc3: /*CCR3*/ + ccr3 = val; + break; + case 0xe8: /*CCR4*/ + if ((ccr3 & 0xf0) == 0x10) + { + ccr4 = val; + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type >= CPU_Cx6x86) + { + if (val & 0x80) + CPUID = models[model].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; + else + CPUID = 0; + } + } + break; + case 0xe9: /*CCR5*/ + if ((ccr3 & 0xf0) == 0x10) + ccr5 = val; + break; + case 0xea: /*CCR6*/ + if ((ccr3 & 0xf0) == 0x10) + ccr6 = val; + break; + } +} + +uint8_t cyrix_read(uint16_t addr, void *priv) +{ + if (addr & 1) + { + switch (cyrix_addr) + { + case 0xc0: return ccr0; + case 0xc1: return ccr1; + case 0xc2: return ccr2; + case 0xc3: return ccr3; + case 0xe8: return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + case 0xe9: return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + case 0xea: return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + case 0xfe: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id & 0xff; + case 0xff: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id >> 8; + } + if ((cyrix_addr & 0xf0) == 0xc0) return 0xff; + if (cyrix_addr == 0x20 && models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_Cx5x86) return 0xff; + } + return 0xff; +} + +void x86_setopcodes(OpFn *opcodes, OpFn *opcodes_0f, OpFn *dynarec_opcodes, OpFn *dynarec_opcodes_0f) +{ + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; + x86_dynarec_opcodes = dynarec_opcodes; + x86_dynarec_opcodes_0f = dynarec_opcodes_0f; +} diff --git a/src/cpu.h b/src/cpu.h new file mode 100644 index 000000000..a6d20a365 --- /dev/null +++ b/src/cpu.h @@ -0,0 +1,146 @@ +#ifndef _CPU_H_ +#define _CPU_H_ + +extern int cpu, cpu_manufacturer; + +/*808x class CPUs*/ +#define CPU_8088 0 +#define CPU_8086 1 + +/*286 class CPUs*/ +#define CPU_286 2 + +/*386 class CPUs*/ +#define CPU_386SX 3 +#define CPU_386DX 4 +#define CPU_486SLC 5 +#define CPU_486DLC 6 + +/*486 class CPUs*/ +#define CPU_i486SX 7 +#define CPU_Am486SX 8 +#define CPU_Cx486S 9 +#define CPU_i486DX 10 +#define CPU_Am486DX 11 +#define CPU_Cx486DX 12 +#define CPU_Cx5x86 13 + +/*586 class CPUs*/ +#define CPU_WINCHIP 14 +#define CPU_PENTIUM 15 +#define CPU_PENTIUMMMX 16 +#define CPU_Cx6x86 17 +#define CPU_Cx6x86MX 18 +#define CPU_Cx6x86L 19 +#define CPU_CxGX1 20 +#define CPU_K5 21 +#define CPU_5K86 22 +#define CPU_K6 23 + +/*686 class CPUs*/ +#define CPU_PENTIUMPRO 24 +#define CPU_PENTIUM2 25 +#define CPU_PENTIUM2D 26 + +#define MANU_INTEL 0 +#define MANU_AMD 1 +#define MANU_CYRIX 2 +#define MANU_IDT 3 + +extern int timing_rr; +extern int timing_mr, timing_mrl; +extern int timing_rm, timing_rml; +extern int timing_mm, timing_mml; +extern int timing_bt, timing_bnt; + +extern int timing_int, timing_int_rm, timing_int_v86, timing_int_pm, timing_int_pm_outer; +extern int timing_iret_rm, timing_iret_v86, timing_iret_pm, timing_iret_pm_outer; +extern int timing_call_rm, timing_call_pm, timing_call_pm_gate, timing_call_pm_gate_inner; +extern int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +extern int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; + + +typedef struct +{ + char name[32]; + int cpu_type; + int speed; + int rspeed; + int multi; + int pci_speed; + uint32_t edx_reset; + uint32_t cpuid_model; + uint16_t cyrix_id; + int cpu_flags; +} CPU; + +extern CPU cpus_8088[]; +extern CPU cpus_8086[]; +extern CPU cpus_286[]; +extern CPU cpus_i386[]; +extern CPU cpus_Am386[]; +extern CPU cpus_486SDLC[]; +extern CPU cpus_i486[]; +extern CPU cpus_Am486[]; +extern CPU cpus_Cx486[]; +extern CPU cpus_WinChip[]; +extern CPU cpus_Pentium5V[]; +extern CPU cpus_Pentium5V50[]; +extern CPU cpus_PentiumS5[]; +extern CPU cpus_K5[]; +extern CPU cpus_K56[]; +extern CPU cpus_Pentium[]; +extern CPU cpus_6x86[]; +extern CPU cpus_PentiumPro[]; +extern CPU cpus_Pentium2[]; +extern CPU cpus_Pentium2D[]; + +extern CPU cpus_pcjr[]; +extern CPU cpus_pc1512[]; +extern CPU cpus_ibmat[]; +extern CPU cpus_ps1_m2011[]; +extern CPU cpus_acer[]; + +extern int cpu_iscyrix; +extern int cpu_16bitbus; +extern int cpu_busspeed; +extern int cpu_multi; + +extern int cpu_hasrdtsc; +extern int cpu_hasMSR; +extern int cpu_hasMMX; +extern int cpu_hasCR4; + +#define CR4_TSD (1 << 2) +#define CR4_DE (1 << 3) +#define CR4_MCE (1 << 6) +#define CR4_PCE (1 << 8) +#define CR4_OSFXSR (1 << 9) + +extern uint64_t cpu_CR4_mask; + +#define CPU_SUPPORTS_DYNAREC 1 +// #define CPU_REQUIRES_DYNAREC 2 +#define CPU_REQUIRES_DYNAREC 0 + +extern uint64_t tsc; + +void cyrix_write(uint16_t addr, uint8_t val, void *priv); +uint8_t cyrix_read(uint16_t addr, void *priv); + +extern int is8086; + +void cpu_CPUID(); + +void cpu_RDMSR(); +void cpu_WRMSR(); + +extern int cpu_use_dynarec; + +extern int xt_cpu_multi; + +#define ISA_CYCLES_SHIFT 6 +extern int isa_cycles; +#define ISA_CYCLES(x) ((x * isa_cycles) >> ISA_CYCLES_SHIFT) + +#endif diff --git a/src/dac.c b/src/dac.c new file mode 100644 index 000000000..b09b2fe13 --- /dev/null +++ b/src/dac.c @@ -0,0 +1,68 @@ +#include "ibm.h" + +uint8_t dac,dac2; +uint8_t dacctrl; +int lptfifo; +uint8_t dssbuffer[16]; +int dssstart=0,dssend=0; +int dssmode=0; + +void writedac(uint16_t addr, uint8_t val) +{ + if (dssmode) dac2=val; + else dac=val; +} + +void writedacctrl(uint16_t addr, uint8_t val) +{ +// printf("Write DAC ctrl %02X %i\n",val,lptfifo); + if (dacctrl&8 && !(val&8) && (lptfifo!=16)) + { +// dac=dac2; + dssbuffer[dssend++]=dac2; + dssend&=15; + lptfifo++; + } + dacctrl=val; +} + +uint8_t readdacfifo() +{ + if (lptfifo==16) return 0x40; + return 0; +} + +void pollss() +{ + if (lptfifo) + { + dac=dssbuffer[dssstart++]; + dssstart&=15; + lptfifo--; + } +} + +int16_t dacbuffer[SOUNDBUFLEN+20]; +int dacbufferpos=0; +void getdacsamp() +{ + if (dacbufferposSOUNDBUFLEN) dacbufferpos=SOUNDBUFLEN; + for (c=0;c= 256) + fatal("device_add : too many devices\n"); + + current_device = d; + + priv = d->init(); + if (priv == NULL) + fatal("device_add : device init failed\n"); + + devices[c] = d; + device_priv[c] = priv; +} + +void device_close_all() +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + devices[c]->close(device_priv[c]); + devices[c] = device_priv[c] = NULL; + } + } +} + +int device_available(device_t *d) +{ +#ifdef RELEASE_BUILD + if (d->flags & DEVICE_NOT_WORKING) + return 0; +#endif + if (d->available) + return d->available(); + + return 1; +} + +void device_speed_changed() +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + if (devices[c]->speed_changed != NULL) + { + devices[c]->speed_changed(device_priv[c]); + } + } + } + + sound_speed_changed(); +} + +void device_force_redraw() +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + if (devices[c]->force_redraw != NULL) + { + devices[c]->force_redraw(device_priv[c]); + } + } + } +} + +char *device_add_status_info(char *s, int max_len) +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + if (devices[c]->add_status_info != NULL) + devices[c]->add_status_info(s, max_len, device_priv[c]); + } + } +} + +int device_get_config_int(char *s) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + return config_get_int(current_device->name, s, config->default_int); + + config++; + } + return 0; +} + +char *device_get_config_string(char *s) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + return config_get_string(current_device->name, s, config->default_string); + + config++; + } + return NULL; +} diff --git a/src/device.h b/src/device.h new file mode 100644 index 000000000..ffb3ea35b --- /dev/null +++ b/src/device.h @@ -0,0 +1,50 @@ +#define CONFIG_STRING 0 +#define CONFIG_INT 1 +#define CONFIG_BINARY 2 +#define CONFIG_SELECTION 3 +#define CONFIG_MIDI 4 + +typedef struct device_config_selection_t +{ + char description[256]; + int value; +} device_config_selection_t; + +typedef struct device_config_t +{ + char name[256]; + char description[256]; + int type; + char default_string[256]; + int default_int; + device_config_selection_t selection[16]; +} device_config_t; + +typedef struct device_t +{ + char name[50]; + uint32_t flags; + void *(*init)(); + void (*close)(void *p); + int (*available)(); + void (*speed_changed)(void *p); + void (*force_redraw)(void *p); + void (*add_status_info)(char *s, int max_len, void *p); + device_config_t *config; +} device_t; + +void device_init(); +void device_add(device_t *d); +void device_close_all(); +int device_available(device_t *d); +void device_speed_changed(); +void device_force_redraw(); +char *device_add_status_info(char *s, int max_len); + +int device_get_config_int(char *name); +char *device_get_config_string(char *name); + +enum +{ + DEVICE_NOT_WORKING = 1 /*Device does not currently work correctly and will be disabled in a release build*/ +}; diff --git a/src/disc.c b/src/disc.c new file mode 100644 index 000000000..44ace5cc5 --- /dev/null +++ b/src/disc.c @@ -0,0 +1,453 @@ +#include "ibm.h" + +#include "config.h" +#include "disc.h" +#include "disc_fdi.h" +#include "disc_img.h" +#include "fdc.h" +#include "fdd.h" +#include "pit.h" +#include "timer.h" +#include "disc_sector.h" + +int disc_drivesel = 0; +int disc_poll_time = 16; + +int poll_time[2] = {16, 16}; + +int disc_track[2]; +int writeprot[2], fwriteprot[2]; + +DRIVE drives[2]; +int drive_type[2]; + +int curdrive = 0; + +int swwp = 0; +int disable_write = 0; + +//char discfns[2][260] = {"", ""}; +int defaultwriteprot = 0; + +int fdc_time; +int disc_time; + +int fdc_ready; + +int drive_empty[2] = {1, 1}; +int disc_changed[2]; + +int bpulses[2] = {0, 0}; + +int motorspin; +int motoron; + +int fdc_indexcount = 52; + +/*void (*fdc_callback)(); +void (*fdc_data)(uint8_t dat); +void (*fdc_spindown)(); +void (*fdc_finishread)(); +void (*fdc_notfound)(); +void (*fdc_datacrcerror)(); +void (*fdc_headercrcerror)(); +void (*fdc_writeprotect)(); +int (*fdc_getdata)(int last); +void (*fdc_sectorid)(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2); +void (*fdc_indexpulse)();*/ + +static struct +{ + char *ext; + void (*load)(int drive, char *fn); + void (*close)(int drive); + int size; +} +loaders[]= +{ + {"IMG", img_load, img_close, -1}, + {"IMA", img_load, img_close, -1}, + {"360", img_load, img_close, -1}, + {"XDF", img_load, img_close, -1}, + {"FDI", fdi_load, fdi_close, -1}, + {0,0,0} +}; + +static int driveloaders[4]; + +void disc_load(int drive, char *fn) +{ + int c = 0, size; + char *p; + FILE *f; +// pclog("disc_load %i %s\n", drive, fn); +// setejecttext(drive, ""); + fdd_stepping_motor_on[drive] = fdd_track_diff[drive] = NULL; + if (!fn) return; + p = get_extension(fn); + if (!p) return; +// setejecttext(drive, fn); + pclog("Loading :%i %s %s\n", drive, fn,p); + f = fopen(fn, "rb"); + if (!f) return; + fseek(f, -1, SEEK_END); + size = ftell(f) + 1; + fclose(f); + while (loaders[c].ext) + { + if (!strcasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) + { + pclog("Loading as %s\n", p); + driveloaders[drive] = c; + loaders[c].load(drive, fn); + drive_empty[drive] = 0; + disc_changed[drive] = 1; + strcpy(discfns[drive], fn); + return; + } + c++; + } + pclog("Couldn't load %s %s\n",fn,p); + drive_empty[drive] = 1; + discfns[drive][0] = 0; +} + +void disc_close(int drive) +{ +// pclog("disc_close %i\n", drive); + if (loaders[driveloaders[drive]].close) loaders[driveloaders[drive]].close(drive); + drive_empty[drive] = 1; + discfns[drive][0] = 0; + drives[drive].hole = NULL; + drives[drive].poll = NULL; + drives[drive].seek = NULL; + drives[drive].readsector = NULL; + drives[drive].writesector = NULL; + drives[drive].readaddress = NULL; + drives[drive].format = NULL; + drives[drive].realtrack = NULL; + drives[drive].stop = NULL; + fdd_stepping_motor_on[drive] = fdd_track_diff[drive] = 0; +} + +int disc_notfound=0; +int not_found[2] = {0, 0}; +static int disc_period = 32; + +int disc_hole(int drive) +{ + drive ^= fdd_swap; + + if (drives[drive].hole) + { + return drives[drive].hole(drive); + } + else + { + return 0; + } +} + +int disc_byteperiod(int drive) +{ + drive ^= fdd_swap; + + if (drives[drive].byteperiod) + { + return drives[drive].byteperiod(drive); + } + else + { + return 32; + } +} + +#define ACCURATE_TIMER_USEC ((((double) cpuclock) / 1000000.0) * (double)(1 << TIMER_SHIFT)) + +uint32_t byte_pulses = 0; + +#if 0 +void disc_time_adjust() +{ + if (disc_byteperiod(disc_drivesel ^ fdd_swap) == 26) + disc_poll_time -= ((160.0 / 6.0) * ACCURATE_TIMER_USEC); + else + disc_poll_time -= 25.0 * ((double) disc_byteperiod(disc_drivesel ^ fdd_swap)) * ACCURATE_TIMER_USEC; +} + +void disc_poll() +{ + // disc_poll_time += disc_period * TIMER_USEC; + if (disc_byteperiod(disc_drivesel ^ fdd_swap) == 26) + disc_poll_time += ((160.0 / 6.0) * ACCURATE_TIMER_USEC); + else + disc_poll_time += ((double) disc_byteperiod(disc_drivesel ^ fdd_swap)) * ACCURATE_TIMER_USEC; + + byte_pulses++; + if ((byte_pulses > 6250) && (byte_pulses <= 6275)) pclog("Byte pulses is now %i!\n", byte_pulses); + + if (drives[disc_drivesel].poll) + drives[disc_drivesel].poll(disc_drivesel); + + if (disc_notfound) + { + disc_notfound--; + if (!disc_notfound) + fdc_notfound(); + } +} +#endif + +// #define TIMER_SUB 441 // 736 +// #define TIMER_SUB 0 +#define TIMER_SUB 0 + +double dt[2] = {0.0, 0.0}; +double dt2[2] = {0.0, 0.0}; + +void disc_poll_ex(int poll_drive) +{ + int dp = 0; + double pm = 1.0; + + int dbp = disc_byteperiod(poll_drive ^ fdd_swap); + double ddbp = (double) dbp; + + double dtime = 0.0; + + double dusec = (double) TIMER_USEC; + double dsub = (double) TIMER_SUB; + + if (dbp == 26) ddbp = 160.0 / 6.0; + + if (not_found[poll_drive]) + { + not_found[poll_drive]--; + if (!not_found[poll_drive]) + fdc_notfound(); + } + else + { + if (drives[poll_drive].poll) + dp = drives[poll_drive].poll(poll_drive); + } + +#if 0 + if (dp == 2) + { + pm = 15.0 / 16.0; + pclog("SYNC byte detected\n"); + } +#endif + + dtime = (ddbp * pm * dusec) - dsub; + + poll_time[poll_drive] += (int) dtime; + + dt[poll_drive] += dtime; + if (dp) dt2[poll_drive] += dtime; + + if (dp) bpulses[poll_drive]++; + + // if (!dp && (byte_pulses == 10416)) + if (bpulses[poll_drive] == raw_tsize[poll_drive]) + { + pclog("Sent %i byte pulses for drive %c (time: %lf | %lf)\n", raw_tsize[poll_drive], 0x41 + poll_drive, dt[poll_drive], dt2[poll_drive]); + // poll_time[poll_drive] += (dbp * (2.0 / 3.0) * pm * TIMER_USEC) - TIMER_SUB; + // dt[poll_drive] = dt2[poll_drive] = bpulses[poll_drive] = motor_on[poll_drive] = 0; + // disc_stop(poll_drive ^ fdd_swap); /* Send drive to idle state after enough byte pulses have been sent. */ + /* Disc state is already set to idle on finish or error anyway. */ + } +} + +void disc_poll_0() +{ + disc_poll_ex(0); +} + +void disc_poll_1() +{ + disc_poll_ex(1); +} + +int disc_get_bitcell_period(int rate) +{ + int bit_rate; + + switch (rate) + { + case 0: /*High density*/ + bit_rate = 500; + break; + case 1: /*Double density (360 rpm)*/ + bit_rate = 300; + break; + case 2: /*Double density*/ + bit_rate = 250; + break; + case 3: /*Extended density*/ + bit_rate = 1000; + break; + } + + return 1000000 / bit_rate*2; /*Bitcell period in ns*/ +} + + +void disc_set_rate(int drive, int drvden, int rate) +{ + switch (rate) + { + case 0: /*High density*/ + disc_period = 16; + break; + case 1: + switch(drvden) + { + case 0: /*Double density (360 rpm)*/ + disc_period = 26; + break; + case 1: /*High density (360 rpm)*/ + disc_period = 16; + break; + case 2: + disc_period = 4; + break; + } + case 2: /*Double density*/ + disc_period = 32; + break; + case 3: /*Extended density*/ + disc_period = 8; + break; + } +} + +void disc_reset() +{ + curdrive = 0; + disc_period = 32; + fdd_stepping_motor_on[0] = fdd_track_diff[0] = 0; + fdd_stepping_motor_on[1] = fdd_track_diff[1] = 0; + // timer_add(disc_poll, &disc_poll_time, &motoron, NULL); + timer_add(disc_poll_0, &(poll_time[0]), &(motor_on[0]), NULL); + timer_add(disc_poll_1, &(poll_time[1]), &(motor_on[1]), NULL); +} + +void disc_init() +{ +// pclog("disc_init %p\n", drives); + drives[0].poll = drives[1].poll = 0; + drives[0].seek = drives[1].seek = 0; + drives[0].readsector = drives[1].readsector = 0; + disc_reset(); +} + +int oldtrack[2] = {0, 0}; +void disc_seek(int drive, int track) +{ +// pclog("disc_seek: drive=%i track=%i\n", drive, track); + if (drives[drive].seek) + drives[drive].seek(drive, track); +// if (track != oldtrack[drive]) +// fdc_discchange_clear(drive); +// ddnoise_seek(track - oldtrack[drive]); +// oldtrack[drive] = track; +} + +void disc_readsector(int drive, int sector, int track, int side, int density, int sector_size) +{ + drive ^= fdd_swap; + + if (drives[drive].readsector) + { + drives[drive].readsector(drive, sector, track, side, density, sector_size); + pclog("Byte pulses: %i\n", bpulses[drive]); + bpulses[drive] = 0; + dt[drive] = dt2[drive] = 0; + // motor_on[drive] = 1; + poll_time[drive] = 0; + } + else + not_found[drive] = 1000; +#if 0 + disc_notfound = 1000; +#endif +} + +void disc_writesector(int drive, int sector, int track, int side, int density, int sector_size) +{ + drive ^= fdd_swap; + + if (drives[drive].writesector) + { + drives[drive].writesector(drive, sector, track, side, density, sector_size); + bpulses[drive] = 0; + dt[drive] = dt2[drive] = 0; + // motor_on[drive] = 1; + poll_time[drive] = 0; + } + else + not_found[drive] = 1000; +#if 0 + disc_notfound = 1000; +#endif +} + +void disc_readaddress(int drive, int track, int side, int density) +{ + drive ^= fdd_swap; + + if (drives[drive].readaddress) + { + drives[drive].readaddress(drive, track, side, density); + bpulses[drive] = 0; + dt[drive] = dt2[drive] = 0; + // motor_on[drive] = 1; + poll_time[drive] = 0; + } +} + +void disc_format(int drive, int track, int side, int density, uint8_t fill) +{ + drive ^= fdd_swap; + + if (drives[drive].format) + { + drives[drive].format(drive, track, side, density, fill); + bpulses[drive] = 0; + dt[drive] = dt2[drive] = 0; + // motor_on[drive] = 1; + poll_time[drive] = 0; + } + else + not_found[drive] = 1000; +#if 0 + disc_notfound = 1000; +#endif +} + +int disc_realtrack(int drive, int track) +{ + drive ^= fdd_swap; + + if (drives[drive].realtrack) + return drives[drive].realtrack(drive, track); + else + return track; +} + +void disc_stop(int drive) +{ + drive ^= fdd_swap; + + if (drives[drive].stop) + drives[drive].stop(drive); +} + +void disc_set_drivesel(int drive) +{ + drive ^= fdd_swap; + + disc_drivesel = drive; +} diff --git a/src/disc.h b/src/disc.h new file mode 100644 index 000000000..eca729570 --- /dev/null +++ b/src/disc.h @@ -0,0 +1,83 @@ +typedef struct +{ + void (*seek)(int drive, int track); + void (*readsector)(int drive, int sector, int track, int side, int density, int sector_size); + void (*writesector)(int drive, int sector, int track, int side, int density, int sector_size); + void (*readaddress)(int drive, int track, int side, int density); + void (*format)(int drive, int track, int side, int density, uint8_t fill); + int (*hole)(int drive); + int (*byteperiod)(int drive); + void (*stop)(int drive); + int (*poll)(int drive); + int (*realtrack)(int drive, int track); +} DRIVE; + +extern DRIVE drives[2]; + +extern int curdrive; + +void disc_load(int drive, char *fn); +void disc_new(int drive, char *fn); +void disc_close(int drive); +void disc_init(); +void disc_reset(); +void disc_poll(); +void disc_seek(int drive, int track); +void disc_readsector(int drive, int sector, int track, int side, int density, int sector_size); +void disc_writesector(int drive, int sector, int track, int side, int density, int sector_size); +void disc_readaddress(int drive, int track, int side, int density); +void disc_format(int drive, int track, int side, int density, uint8_t fill); +void disc_time_adjust(); +int disc_realtrack(int drive, int track); +int disc_hole(int drive); +int disc_byteperiod(int drive); +void disc_stop(int drive); +int disc_empty(int drive); +void disc_set_rate(int drive, int drvden, int rate); +void disc_set_drivesel(int drive); +extern int disc_time; +extern int disc_poll_time; +extern int poll_time[2]; +extern int disc_drivesel; +extern int disc_notfound; +extern int not_found[2]; + +void fdc_callback(); +int fdc_data(uint8_t dat); +void fdc_spindown(); +void fdc_finishread(); +void fdc_notfound(); +void fdc_datacrcerror(); +void fdc_headercrcerror(); +void fdc_writeprotect(); +int fdc_getdata(int last); +void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2); +void fdc_indexpulse(); +/*extern int fdc_time; +extern int fdc_ready; +extern int fdc_indexcount;*/ + +extern int motorspin; +extern int motoron; + +extern int motor_on[2]; + +extern int swwp; +extern int disable_write; + +extern int defaultwriteprot; +//extern char discfns[4][260]; + +extern int writeprot[2], fwriteprot[2]; +extern int disc_track[2]; +extern int disc_changed[2]; +extern int drive_empty[2]; +extern int drive_type[2]; + +extern uint32_t byte_pulses; + +extern int bpulses[2]; + +/*Used in the Read A Track command. Only valid for disc_readsector(). */ +#define SECTOR_FIRST -2 +#define SECTOR_NEXT -1 diff --git a/src/disc_fdi.c b/src/disc_fdi.c new file mode 100644 index 000000000..1bda2ff44 --- /dev/null +++ b/src/disc_fdi.c @@ -0,0 +1,513 @@ +#include +#include +#include "ibm.h" +#include "disc.h" +#include "disc_fdi.h" +#include "fdi2raw.h" + +static struct +{ + FILE *f; + FDI *h; + uint8_t track_data[2][4][256*1024]; + + int sides; + int tracklen[2][4]; + int trackindex[2][4]; + + int lasttrack; +} fdi[2]; + +static uint8_t fdi_timing[256*1024]; +#if 0 +static int fdi_pos; +static int fdi_revs; + +static int fdi_sector, fdi_track, fdi_side, fdi_drive, fdi_density, fdi_n; +static int fdi_inread, fdi_inwrite, fdi_readpos, fdi_inreadaddr; +#endif + +static int fdi_pos[2]; +static int fdi_revs[2]; + +static int fdi_sector[2], fdi_track[2], fdi_side[2], fdi_drive[2], fdi_density[2], fdi_n[2]; +static int fdi_inread[2], fdi_inwrite[2], fdi_readpos[2], fdi_inreadaddr[2]; + +static uint16_t CRCTable[256]; + +static int pollbytesleft[2]={0, 0},pollbitsleft[2]={0, 0}; + +int fdi_realtrack(int drive, int track) +{ + return track; +} + +static void fdi_setupcrc(uint16_t poly, uint16_t rvalue) +{ + int c = 256, bc; + uint16_t crctemp; + + while(c--) + { + crctemp = c << 8; + bc = 8; + + while(bc--) + { + if(crctemp & 0x8000) + { + crctemp = (crctemp << 1) ^ poly; + } + else + { + crctemp <<= 1; + } + } + + CRCTable[c] = crctemp; + } +} + +void fdi_init() +{ +// printf("FDI reset\n"); + memset(&fdi, 0, sizeof(fdi)); + fdi_setupcrc(0x1021, 0xcdb4); +} + +int fdi_hole(int drive) +{ + switch (fdi2raw_get_bit_rate(fdi[drive].h)) + { + case 1000: + return 2; + case 500: + return 1; + default: + return 0; + } +} + +int fdi_byteperiod(int drive) +{ + switch (fdi2raw_get_bit_rate(fdi[drive].h)) + { + case 1000: + return 8; + case 500: + return 16; + case 300: + return 26; + case 250: + return 32; + default: + return 0; + } +} + +void fdi_load(int drive, char *fn) +{ + writeprot[drive] = fwriteprot[drive] = 1; + fdi[drive].f = fopen(fn, "rb"); + if (!fdi[drive].f) return; + fdi[drive].h = fdi2raw_header(fdi[drive].f); +// if (!fdih[drive]) printf("Failed to load!\n"); + fdi[drive].lasttrack = fdi2raw_get_last_track(fdi[drive].h); + fdi[drive].sides = fdi2raw_get_last_head(fdi[drive].h) + 1; +// printf("Last track %i\n",fdilasttrack[drive]); + drives[drive].seek = fdi_seek; + drives[drive].readsector = fdi_readsector; + drives[drive].writesector = fdi_writesector; + drives[drive].readaddress = fdi_readaddress; + drives[drive].hole = fdi_hole; + drives[drive].byteperiod = fdi_byteperiod; + drives[drive].poll = fdi_poll; + drives[drive].format = fdi_format; + drives[drive].stop = fdi_stop; + drives[drive].realtrack = fdi_realtrack; +// pclog("Loaded as FDI\n"); +} + +void fdi_close(int drive) +{ + if (fdi[drive].h) + fdi2raw_header_free(fdi[drive].h); + if (fdi[drive].f) + fclose(fdi[drive].f); + fdi[drive].f = NULL; +} + +void fdi_seek(int drive, int track) +{ + int c; + int density; + + if (!fdi[drive].f) + return; +// printf("Track start %i\n",track); + if (track < 0) + track = 0; + if (track > fdi[drive].lasttrack) + track = fdi[drive].lasttrack - 1; + + for (density = 0; density < 4; density++) + { + int c = fdi2raw_loadtrack(fdi[drive].h, (uint16_t *)fdi[drive].track_data[0][density], + (uint16_t *)fdi_timing, + track * fdi[drive].sides, + &fdi[drive].tracklen[0][density], + &fdi[drive].trackindex[0][density], NULL, density); + if (!c) + memset(fdi[drive].track_data[0][density], 0, fdi[drive].tracklen[0][density]); + + if (fdi[drive].sides == 2) + { + c = fdi2raw_loadtrack(fdi[drive].h, (uint16_t *)fdi[drive].track_data[1][density], + (uint16_t *)fdi_timing, + (track * fdi[drive].sides) + 1, + &fdi[drive].tracklen[1][density], + &fdi[drive].trackindex[1][density], NULL, density); + if (!c) + memset(fdi[drive].track_data[1][density], 0, fdi[drive].tracklen[1][density]); + } + else + { + memset(fdi[drive].track_data[1][density], 0, 65536); + fdi[drive].tracklen[0][density] = fdi[drive].tracklen[1][density] = 10000; + } + } +} + +void fdi_writeback(int drive, int track) +{ + return; +} + +void fdi_readsector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + fdi_revs[drive] = 0; + fdi_sector[drive] = sector; + fdi_track[drive] = track; + fdi_side[drive] = side; + fdi_n[drive] = sector_size; + // fdi_drive = drive; + if (rate == 2) + fdi_density[drive] = 1; + if (rate == 0) + fdi_density[drive] = 2; + if (rate == 3) + fdi_density[drive] = 3; + +// pclog("FDI Read sector %i %i %i %i %i\n",drive,side,track,sector, fdi_density); +// if (pollbytesleft) +// pclog("In the middle of a sector!\n"); + + fdi_inread[drive] = 1; + fdi_inwrite[drive] = 0; + fdi_inreadaddr[drive] = 0; + fdi_readpos[drive] = 0; +} + +void fdi_writesector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + fdi_revs[drive] = 0; + fdi_sector[drive] = sector; + fdi_track[drive] = track; + fdi_side[drive] = side; + fdi_n[drive] = sector_size; + // fdi_drive = drive; + if (rate == 2) + fdi_density[drive] = 1; + if (rate == 0) + fdi_density[drive] = 2; + if (rate == 3) + fdi_density[drive] = 3; +// pclog("Write sector %i %i %i %i\n",drive,side,track,sector); + + fdi_inread[drive] = 0; + fdi_inwrite[drive] = 1; + fdi_inreadaddr[drive] = 0; + fdi_readpos[drive] = 0; +} + +void fdi_readaddress(int drive, int track, int side, int rate) +{ + fdi_revs[drive] = 0; + fdi_track[drive] = track; + fdi_side[drive] = side; + // fdi_drive = drive; + if (rate == 2) + fdi_density[drive] = 1; + if (rate == 0) + fdi_density[drive] = 2; + if (rate == 3) + fdi_density[drive] = 3; +// pclog("Read address %i %i %i %i %i %p\n",drive,side,track, rate, fdi_density, &fdi_inreadaddr); + + fdi_inread[drive] = 0; + fdi_inwrite[drive] = 0; + fdi_inreadaddr[drive] = 1; + fdi_readpos[drive] = 0; +} + +void fdi_format(int drive, int track, int side, int rate, uint8_t fill) +{ + fdi_revs[drive] = 0; + fdi_track[drive] = track; + fdi_side[drive] = side; + // fdi_drive = drive; + if (rate == 2) + fdi_density[drive] = 1; + if (rate == 0) + fdi_density[drive] = 2; + if (rate == 3) + fdi_density[drive] = 3; +// pclog("Format %i %i %i\n",drive,side,track); + + fdi_inread[drive] = 0; + fdi_inwrite[drive] = 1; + fdi_inreadaddr[drive] = 0; + fdi_readpos[drive] = 0; +} + +static uint16_t fdi_buffer[2]; +static int readidpoll[2]={0, 0},readdatapoll[2]={0, 0},fdi_nextsector[2]={0, 0},inreadop[2]={0, 0}; +static uint8_t fdi_sectordat[2][1026]; +static int lastfdidat[2][2],sectorcrc[2][2]; +static int sectorsize[2],fdc_sectorsize[2]; +static int ddidbitsleft[2]={0, 0}; + +static uint8_t decodefm(uint16_t dat) +{ + uint8_t temp; + temp = 0; + if (dat & 0x0001) temp |= 1; + if (dat & 0x0004) temp |= 2; + if (dat & 0x0010) temp |= 4; + if (dat & 0x0040) temp |= 8; + if (dat & 0x0100) temp |= 16; + if (dat & 0x0400) temp |= 32; + if (dat & 0x1000) temp |= 64; + if (dat & 0x4000) temp |= 128; + return temp; +} + +void fdi_stop(int drive) +{ +// pclog("fdi_stop\n"); + fdi_inread[drive] = fdi_inwrite[drive] = fdi_inreadaddr[drive] = 0; + fdi_nextsector[drive] = ddidbitsleft[drive] = pollbitsleft[drive] = 0; +} + +static uint16_t crc[2]; + +static void calccrc(int drive, uint8_t byte) +{ + crc[drive] = (crc[drive] << 8) ^ CRCTable[(crc[drive] >> 8)^byte]; +} + +static int fdi_indextime_blank[2] = {6250 * 8, 6250 * 8}; +int fdi_poll(int drive) +{ + int tempi, c; + int bitcount; + + for (bitcount = 0; bitcount < 16; bitcount++) + { + if (fdi_pos[drive] >= fdi[drive].tracklen[fdi_side[drive]][fdi_density[drive]]) + { + fdi_pos[drive] = 0; + if (fdi[drive].tracklen[fdi_side[drive]][fdi_density[drive]]) + fdc_indexpulse(); + else + { + fdi_indextime_blank[drive]--; + if (!fdi_indextime_blank[drive]) + { + fdi_indextime_blank[drive] = 6250 * 8; + fdc_indexpulse(); + } + } + } + tempi = fdi[drive].track_data[fdi_side[drive]][fdi_density[drive]][((fdi_pos[drive] >> 3) & 0xFFFF) ^ 1] & (1 << (7 - (fdi_pos[drive] & 7))); + fdi_pos[drive]++; + fdi_buffer[drive] <<= 1; + fdi_buffer[drive] |= (tempi ? 1 : 0); + if (fdi_inwrite[drive]) + { + fdi_inwrite[drive] = 0; + fdc_writeprotect(); + return 1; + } + if (!fdi_inread[drive] && !fdi_inreadaddr[drive]) + return 1; + if (fdi_pos[drive] == fdi[drive].trackindex[fdi_side[drive]][fdi_density[drive]]) + { + fdi_revs[drive]++; + if (fdi_revs[drive] == 3) + { +// pclog("Not found!\n"); + fdc_notfound(); + fdi_inread[drive] = fdi_inreadaddr[drive] = 0; + return 1; + } + if (fdi_sector[drive] == SECTOR_FIRST) + fdi_sector[drive] = SECTOR_NEXT; + } + if (pollbitsleft[drive]) + { + pollbitsleft[drive]--; + if (!pollbitsleft[drive]) + { + pollbytesleft[drive]--; + if (pollbytesleft[drive]) pollbitsleft[drive] = 16; /*Set up another word if we need it*/ + if (readidpoll[drive]) + { + fdi_sectordat[drive][5 - pollbytesleft[drive]] = decodefm(fdi_buffer[drive]); + if (fdi_inreadaddr[drive] && !fdc_sectorid)// && pollbytesleft[drive] > 1) + { +// rpclog("inreadaddr - %02X\n", fdi_sectordat[drive][5 - pollbytesleft][drive]); + fdc_data(fdi_sectordat[drive][5 - pollbytesleft[drive]]); + } + if (!pollbytesleft[drive]) + { +// pclog("Header over %i,%i %i,%i\n", fdi_sectordat[drive][0], fdi_sectordat[drive][2], fdi_track[drive], fdi_sector[drive]); + if ((fdi_sectordat[drive][0] == fdi_track[drive] && (fdi_sectordat[drive][3] == fdi_n[drive]) && (fdi_sectordat[drive][2] == fdi_sector[drive] || fdi_sector[drive] == SECTOR_NEXT)) || fdi_inreadaddr[drive]) + { + crc[drive] = (fdi_density) ? 0xcdb4 : 0xffff; + calccrc(drive, 0xFE); + for (c = 0; c < 4; c++) + calccrc(drive, fdi_sectordat[drive][c]); + + if ((crc[drive] >> 8) != fdi_sectordat[drive][4] || (crc[drive] & 0xFF) != fdi_sectordat[drive][5]) + { +// pclog("Header CRC error : %02X %02X %02X %02X\n",crc[drive]>>8,crc[drive]&0xFF,fdi_sectordat[drive][4],fdi_sectordat[drive][5]); +// dumpregs(); +// exit(-1); + inreadop[drive] = 0; + if (fdi_inreadaddr[drive]) + { +// rpclog("inreadaddr - %02X\n", fdi_sector[drive]); +// fdc_data(fdi_sector[drive]); + if (fdc_sectorid) + fdc_sectorid(fdi_sectordat[drive][0], fdi_sectordat[drive][1], fdi_sectordat[drive][2], fdi_sectordat[drive][3], fdi_sectordat[drive][4], fdi_sectordat[drive][5]); + else + fdc_finishread(drive); + } + else fdc_headercrcerror(); + return 1; + } +// pclog("Sector %i,%i %i,%i\n", fdi_sectordat[drive][0], fdi_sectordat[drive][2], fdi_track[drive], fdi_sector[drive]); + if (fdi_sectordat[drive][0] == fdi_track[drive] && (fdi_sectordat[drive][2] == fdi_sector[drive] || fdi_sector[drive] == SECTOR_NEXT) && fdi_inread[drive] && !fdi_inreadaddr[drive]) + { + fdi_nextsector[drive] = 1; + readidpoll[drive] = 0; + sectorsize[drive] = (1 << (fdi_sectordat[drive][3] + 7)) + 2; + fdc_sectorsize[drive] = fdi_sectordat[drive][3]; + } + if (fdi_inreadaddr[drive]) + { + if (fdc_sectorid) + fdc_sectorid(fdi_sectordat[drive][0], fdi_sectordat[drive][1], fdi_sectordat[drive][2], fdi_sectordat[drive][3], fdi_sectordat[drive][4], fdi_sectordat[drive][5]); + else + fdc_finishread(drive); + fdi_inreadaddr[drive] = 0; + } + } + } + } + if (readdatapoll[drive]) + { +// pclog("readdatapoll %i %02x\n", pollbytesleft[drive], decodefm(fdi_buffer[drive])); + if (pollbytesleft[drive] > 1) + { + calccrc(drive, decodefm(fdi_buffer[drive])); + } + else + sectorcrc[drive][1 - pollbytesleft[drive]] = decodefm(fdi_buffer[drive]); + if (!pollbytesleft[drive]) + { + fdi_inread[drive] = 0; +//#if 0 + if ((crc[drive] >> 8) != sectorcrc[drive][0] || (crc[drive] & 0xFF) != sectorcrc[drive][1])// || (fditrack[drive]==79 && fdisect[drive]==4 && fdc_side[drive]&1)) + { +// pclog("Data CRC error : %02X %02X %02X %02X %i %04X %02X%02X\n",crc[drive]>>8,crc[drive]&0xFF,sectorcrc[0],sectorcrc[1],fdi_pos,crc,sectorcrc[0],sectorcrc[1]); + inreadop[drive] = 0; + fdc_data(decodefm(lastfdidat[drive][1])); + fdc_finishread(drive); + fdc_datacrcerror(); + readdatapoll[drive] = 0; + return 1; + } +//#endif +// pclog("End of FDI read %02X %02X %02X %02X\n",crc[drive]>>8,crc[drive]&0xFF,sectorcrc[0],sectorcrc[1]); + fdc_data(decodefm(lastfdidat[drive][1])); + fdc_finishread(drive); + } + else if (lastfdidat[drive][1] != 0) + fdc_data(decodefm(lastfdidat[drive][1])); + lastfdidat[drive][1] = lastfdidat[drive][0]; + lastfdidat[drive][0] = fdi_buffer[drive]; + if (!pollbytesleft[drive]) + readdatapoll[drive] = 0; + } + } + } + if (fdi_buffer[drive] == 0x4489 && fdi_density[drive]) + { +// rpclog("Found sync\n"); + ddidbitsleft[drive] = 17; + } + + if (fdi_buffer[drive] == 0xF57E && !fdi_density[drive]) + { + pollbytesleft[drive] = 6; + pollbitsleft[drive] = 16; + readidpoll[drive] = 1; + } + if ((fdi_buffer[drive] == 0xF56F || fdi_buffer[drive] == 0xF56A) && !fdi_density[drive]) + { + if (fdi_nextsector[drive]) + { + pollbytesleft[drive] = sectorsize[drive]; + pollbitsleft[drive] = 16; + readdatapoll[drive] = 1; + fdi_nextsector[drive] = 0; + crc[drive] = 0xffff; + if (fdi_buffer[drive] == 0xF56A) calccrc(drive, 0xF8); + else calccrc(drive, 0xFB); + lastfdidat[drive][0] = lastfdidat[drive][1] = 0; + } + } + if (ddidbitsleft[drive]) + { + ddidbitsleft[drive]--; + if (!ddidbitsleft[drive] && !readdatapoll[drive]) + { +// printf("ID bits over %04X %02X %i\n",fdibuffer[drive],decodefm(fdibuffer[drive]),fdipos[drive]); + if (decodefm(fdi_buffer[drive]) == 0xFE) + { +// printf("Sector header %i %i\n", fdi_inread[drive], fdi_inreadaddr[drive]); + pollbytesleft[drive] = 6; + pollbitsleft[drive] = 16; + readidpoll[drive] = 1; + } + else if (decodefm(fdi_buffer[drive]) == 0xFB) + { +// printf("Data header %i %i\n", fdi_inread[drive], fdi_inreadaddr[drive]); + if (fdi_nextsector[drive]) + { + pollbytesleft[drive] = sectorsize[drive]; + pollbitsleft[drive] = 16; + readdatapoll[drive] = 1; + fdi_nextsector[drive] = 0; + crc[drive] = 0xcdb4; + if (fdi_buffer[drive] == 0xF56A) calccrc(drive, 0xF8); + else calccrc(drive, 0xFB); + lastfdidat[drive][0] = lastfdidat[drive][1] = 0; + } + } + } + } + } +} diff --git a/src/disc_fdi.h b/src/disc_fdi.h new file mode 100644 index 000000000..f62fb165f --- /dev/null +++ b/src/disc_fdi.h @@ -0,0 +1,13 @@ +void fdi_init(); +void fdi_load(int drive, char *fn); +void fdi_close(int drive); +void fdi_seek(int drive, int track); +void fdi_readsector(int drive, int sector, int track, int side, int density, int sector_size); +void fdi_writesector(int drive, int sector, int track, int side, int density, int sector_size); +void fdi_readaddress(int drive, int sector, int side, int density); +void fdi_format(int drive, int sector, int side, int density, uint8_t fill); +int fdi_hole(int drive); +int fdi_byteperiod(int drive); +void fdi_stop(int drive); +int fdi_poll(int drive); +int fdi_realtrack(int track, int drive); diff --git a/src/disc_img.c b/src/disc_img.c new file mode 100644 index 000000000..8700ceb18 --- /dev/null +++ b/src/disc_img.c @@ -0,0 +1,702 @@ +#include "ibm.h" +#include "fdd.h" +#include "disc.h" +#include "disc_img.h" +#include "disc_sector.h" + +static struct +{ + FILE *f; + // uint8_t track_data[2][20*1024]; + uint8_t track_data[2][50000]; + int sectors, tracks, sides; + int sector_size; + int rate; + int xdf_type; /* 0 = not XDF, 1-5 = one of the five XDF types */ + int hole; + int byte_period; + double bitcell_period_300rpm; +} img[2]; + +#if 0 +static uint8_t xdf_track0[5][3]; +static uint8_t xdf_spt[5]; +static uint8_t xdf_map[5][24][3]; +#endif +static uint8_t xdf_track0[3][3]; +static uint8_t xdf_spt[3]; +static uint8_t xdf_map[3][24][3]; +static uint16_t xdf_track0_layout[3][92] = { { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, + 0x8101, 0x8201, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, + 0x0700, 0x0800, 0, 0x8301, 0x8401, 0x8501, 0x8601, 0x8701, + 0x8801, 0x8901, 0x8A01, 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, + 0x9001 }, /* 5.25" 2HD */ + { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, + 0x8900, 0x8A00, 0x8B00, 0x8101, 0x0100, 0x0200, 0x0300, 0x0400, + 0x0500, 0x0600, 0x0700, 0x0800, 0, 0, 0, 0x8201, + 0x8301, 0x8401, 0x8501, 0x8601, 0x8701, 0x8801, 0x8901, 0x8A01, + 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, 0, 0, 0, + 0, 0, 0x9001, 0x9101, 0x9201, 0x9301 }, /* 3.5" 2HD */ + { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, + 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x0100, 0x0200, 0x0300, 0x0400, + 0x0500, 0x0600, 0x0700, 0x0800, 0x9500, 0x9600, 0x9700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0x8D00, 0x8E00, 0x8F00, 0x9000, 0, 0, + 0, 0, 0, 0, 0, 0x9800, 0x9900, 0x9A00, + 0x9B00, 0x9C00, 0x9D00, 0x9E00, 0x8101, 0x8201, 0x8301, 0x8401, + 0x8501, 0x8601, 0x8701, 0x9100, 0x9200, 0x9300, 0x9400, 0x8801, + 0x8901, 0x8A01, 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, 0x9001, + 0x9101, 0x9201, 0x9301, 0x9401, 0x9501, 0x9601, 0x9701, 0x9801, + 0x9901, 0x9A01, 0x9B01, 0x9C01, 0x9D01, 0x9E01, 0x9F01, 0xA001, + 0xA101, 0xA201, 0xA301, 0xA401 }, /* 3.5" 2ED - sectors 0x91 to 0x94 of side 0 are not written to the IMG file but + we read them in from the null-filled areas in order to have them as XDFCOPY + still expects their existence even if it does nothing with them. */ + }; + +/* First dimension is possible sector sizes (0 = 128, 7 = 16384), second is possible bit rates (250/360, 250, 300, 500/360, 500, 1000). */ +/* Disks formatted at 250 kbps @ 360 RPM can be read with a 360 RPM single-RPM 5.25" drive by setting the rate to 250 kbps. + Disks formatted at 300 kbps @ 300 RPM can be read with any 300 RPM single-RPM drive by setting the rate rate to 300 kbps. */ +static uint8_t maximum_sectors[8][6] = { { 26, 31, 38, 53, 64, 118 }, /* 128 */ + { 15, 19, 23, 32, 38, 73 }, /* 256 */ + { 7, 10, 12, 19, 23, 46 }, /* 512 */ + { 3, 5, 6, 9, 11, 22 }, /* 1024 */ + { 2, 2, 3, 4, 5, 11 }, /* 2048 */ + { 1, 1, 1, 2, 2, 5 }, /* 4096 */ + { 0, 0, 0, 1, 1, 3 }, /* 8192 */ + { 0, 0, 0, 0, 0, 1 } }; /* 16384 */ + +static int gap3_sizes[5][8][256] = { [0][1][16] = 0x54, + [0][2][18] = 0x6C, + [0][2][19] = 0x48, + [0][2][20] = 0x2A, + [0][2][21] = 0x0C, + // [0][2][23] = 0x7A, + [0][2][23] = 0x01, + // [0][2][24] = 0x38, + [2][1][10] = 0x32, + [2][1][11] = 0x0C, + [2][1][15] = 0x36, + [2][1][16] = 0x32, + [2][2][8] = 0x58, + [2][2][9] = 0x50, + [2][2][10] = 0x2E, + [2][2][11] = 0x02, + [2][2][21] = 0x1C, + [2][3][4] = 0xF0, + [2][3][5] = 0x74, + [3][2][36] = 0x53, + [3][2][39] = 0x20, + // [3][2][46] = 0x0E, + [3][2][46] = 0x01, + // [3][2][48] = 0x51, + [4][1][32] = 0x36, + [4][2][15] = 0x54, + [4][2][17] = 0x23, + [4][2][18] = 0x02, + // [4][2][19] = 0x29, + [4][2][19] = 0x01, + [4][3][8] = 0x74, + [4][3][9] = 0x74, + [4][3][10] = 0x74 +}; + +/* Needed for formatting! */ +int img_realtrack(int drive, int track) +{ +#ifdef MAINLINE + if ((img[drive].tracks <= 41) && fdd_doublestep_40(drive)) +#else + if ((img[drive].tracks <= 43) && fdd_doublestep_40(drive)) +#endif + track /= 2; + + return track; +} + +void img_writeback(int drive, int track); + +static int img_sector_size_code(int drive) +{ + switch(img[drive].sector_size) + { + case 128: + return 0; + case 256: + return 1; + default: + case 512: + return 2; + case 1024: + return 3; + case 2048: + return 4; + case 4096: + return 5; + case 8192: + return 6; + case 16384: + return 7; + } +} + +static int sector_size_code(int sector_size) +{ + switch(sector_size) + { + case 128: + return 0; + case 256: + return 1; + default: + case 512: + return 2; + case 1024: + return 3; + case 2048: + return 4; + case 4096: + return 5; + case 8192: + return 6; + case 16384: + return 7; + } +} + +void img_init() +{ + memset(img, 0, sizeof(img)); +// adl[0] = adl[1] = 0; +} + +static void add_to_map(uint8_t *arr, uint8_t p1, uint8_t p2, uint8_t p3) +{ + arr[0] = p1; + arr[1] = p2; + arr[2] = p3; +} + +static int xdf_maps_initialized = 0; + +static void initialize_xdf_maps() +{ + // XDF 5.25" 2HD + /* Adds, in this order: sectors per FAT, sectors per each side of track 0, difference between that and virtual sector number specified in BPB. */ + add_to_map(xdf_track0[0], 9, 17, 2); + xdf_spt[0] = 3; + /* Adds, in this order: side, sequential order (not used in PCem), sector size. */ + add_to_map(xdf_map[0][0], 0, 0, 3); + add_to_map(xdf_map[0][1], 0, 2, 6); + add_to_map(xdf_map[0][2], 1, 0, 2); + add_to_map(xdf_map[0][3], 0, 1, 2); + add_to_map(xdf_map[0][4], 1, 2, 6); + add_to_map(xdf_map[0][5], 1, 1, 3); + + // XDF 3.5" 2HD + add_to_map(xdf_track0[1], 11, 19, 4); + xdf_spt[1] = 4; + add_to_map(xdf_map[1][0], 0, 0, 3); + add_to_map(xdf_map[1][1], 0, 2, 4); + add_to_map(xdf_map[1][2], 1, 3, 6); + add_to_map(xdf_map[1][3], 0, 1, 2); + add_to_map(xdf_map[1][4], 1, 1, 2); + add_to_map(xdf_map[1][5], 0, 3, 6); + add_to_map(xdf_map[1][6], 1, 0, 4); + add_to_map(xdf_map[1][7], 1, 2, 3); + + // XDF 3.5" 2ED + add_to_map(xdf_track0[2], 22, 37, 9); + xdf_spt[2] = 4; + add_to_map(xdf_map[2][0], 0, 0, 3); + add_to_map(xdf_map[2][1], 0, 1, 4); + add_to_map(xdf_map[2][2], 0, 2, 5); + add_to_map(xdf_map[2][3], 0, 3, 7); + add_to_map(xdf_map[2][4], 1, 0, 3); + add_to_map(xdf_map[2][5], 1, 1, 4); + add_to_map(xdf_map[2][6], 1, 2, 5); + add_to_map(xdf_map[2][7], 1, 3, 7); + +#if 0 + // XXDF 3.5" 2HD + add_to_map(xdf_track0[3], 12, 20, 4); + xdf_spt[3] = 2; + add_to_map(xdf_map[3][0], 0, 0, 5); + add_to_map(xdf_map[3][1], 1, 1, 6); + add_to_map(xdf_map[3][2], 0, 1, 6); + add_to_map(xdf_map[3][3], 1, 0, 5); + + // XXDF 3.5" 2ED + add_to_map(xdf_track0[4], 21, 39, 9); + xdf_spt[4] = 2; + add_to_map(xdf_map[4][0], 0, 0, 6); + add_to_map(xdf_map[4][1], 1, 1, 7); + add_to_map(xdf_map[4][2], 0, 1, 7); + add_to_map(xdf_map[4][3], 1, 0, 6); +#endif + + xdf_maps_initialized = 1; +} + +void img_load(int drive, char *fn) +{ + int size; + double bit_rate_300; + uint16_t bpb_bps; + uint16_t bpb_total; + uint8_t bpb_mid; /* Media type ID. */ + uint8_t bpb_sectors; + uint8_t bpb_sides; + uint32_t bpt; + uint8_t max_spt; /* Used for XDF detection. */ + int temp_rate; + + if (!xdf_maps_initialized) initialize_xdf_maps(); /* Initialize XDF maps, will need them to properly register sectors in tracks. */ + + writeprot[drive] = 0; + img[drive].f = fopen(fn, "rb+"); + if (!img[drive].f) + { + img[drive].f = fopen(fn, "rb"); + if (!img[drive].f) + return; + writeprot[drive] = 1; + } + fwriteprot[drive] = writeprot[drive]; + + /* Read the BPB */ + fseek(img[drive].f, 0x0B, SEEK_SET); + fread(&bpb_bps, 1, 2, img[drive].f); + fseek(img[drive].f, 0x13, SEEK_SET); + fread(&bpb_total, 1, 2, img[drive].f); + fseek(img[drive].f, 0x15, SEEK_SET); + bpb_mid = fgetc(img[drive].f); + fseek(img[drive].f, 0x18, SEEK_SET); + bpb_sectors = fgetc(img[drive].f); + fseek(img[drive].f, 0x1A, SEEK_SET); + bpb_sides = fgetc(img[drive].f); + + fseek(img[drive].f, -1, SEEK_END); + size = ftell(img[drive].f) + 1; + + img[drive].sides = 2; + img[drive].sector_size = 512; + + img[drive].hole = 0; + + pclog("BPB reports %i sides and %i bytes per sector\n", bpb_sides, bpb_bps); + + if ((bpb_sides < 1) || (bpb_sides > 2) || (bpb_bps < 128) || (bpb_bps > 2048)) + { + /* The BPB is giving us a wacky number of sides and/or bytes per sector, therefore it is most probably + not a BPB at all, so we have to guess the parameters from file size. */ + + if (size <= (160*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; img[drive].sides = 1; bit_rate_300 = 250; raw_tsize[drive] = 6250; } + else if (size <= (180*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; img[drive].sides = 1; bit_rate_300 = 250; raw_tsize[drive] = 6250; } + else if (size <= (320*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; bit_rate_300 = 250; raw_tsize[drive] = 6250; } + else if (size <= (360*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; bit_rate_300 = 250; raw_tsize[drive] = 6250; } /*Double density*/ + else if (size <= (640*1024)) { img[drive].sectors = 8; img[drive].tracks = 80; bit_rate_300 = 250; raw_tsize[drive] = 6250; } /*Double density 640k*/ + else if (size < (1024*1024)) { img[drive].sectors = 9; img[drive].tracks = 80; bit_rate_300 = 250; raw_tsize[drive] = 6250; } /*Double density*/ + else if (size <= 1228800) { img[drive].sectors = 15; img[drive].tracks = 80; bit_rate_300 = (500.0 * 300.0) / 360.0; raw_tsize[drive] = 10416; } /*High density 1.2MB*/ + else if (size <= 1261568) { img[drive].sectors = 8; img[drive].tracks = 77; img[drive].sector_size = 1024; bit_rate_300 = (500.0 * 300.0) / 360.0; raw_tsize[drive] = 10416; } /*High density 1.25MB Japanese format*/ + else if (size <= (0x1A4000-1)) { img[drive].sectors = 18; img[drive].tracks = 80; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*High density (not supported by Tandy 1000)*/ + else if (size <= 1556480) { img[drive].sectors = 19; img[drive].tracks = 80; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*High density (not supported by Tandy 1000)*/ + else if (size <= 1638400) { img[drive].sectors = 10; img[drive].tracks = 80; img[drive].sector_size = 1024; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*High density (not supported by Tandy 1000)*/ + // else if (size == 1884160) { img[drive].sectors = 23; img[drive].tracks = 80; bit_rate_300 = 500; } /*XDF format - used by OS/2 Warp*/ + // else if (size == 1763328) { img[drive].sectors = 21; img[drive].tracks = 82; bit_rate_300 = 500; } /*XDF format - used by OS/2 Warp*/ + else if (size <= 2000000) { img[drive].sectors = 21; img[drive].tracks = 80; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*DMF format - used by Windows 95 - changed by OBattler to 2000000, ie. the real unformatted capacity @ 500 kbps and 300 rpm */ + else if (size <= 2949120) { img[drive].sectors = 36; img[drive].tracks = 80; bit_rate_300 = 1000; raw_tsize[drive] = 25000; } /*E density*/ + + img[drive].xdf_type = 0; + } + else + { + /* The BPB readings appear to be valid, so let's set the values. */ + /* Number of tracks = number of total sectors divided by sides times sectors per track. */ + img[drive].tracks = ((uint32_t) bpb_total) / (((uint32_t) bpb_sides) * ((uint32_t) bpb_sectors)); + /* The rest we just set directly from the BPB. */ + img[drive].sectors = bpb_sectors; + img[drive].sides = bpb_sides; + /* Now we calculate bytes per track, which is bpb_sectors * bpb_bps. */ + bpt = (uint32_t) bpb_sectors * (uint32_t) bpb_bps; + /* Now we should be able to calculate the bit rate. */ + pclog("The image has %i bytes per track\n", bpt); + + temp_rate = 2; + if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][0] * bpb_bps)) + { + bit_rate_300 = ((250.0 * 300.0) / 360.0); + temp_rate = 2; + raw_tsize[drive] = 5208; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][1] * bpb_bps)) + { + bit_rate_300 = 250; + temp_rate = 2; + raw_tsize[drive] = 6250; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][2] * bpb_bps)) + { + bit_rate_300 = 300; + temp_rate = 1; + raw_tsize[drive] = 7500; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][3] * bpb_bps)) + { + bit_rate_300 = (bpb_mid == 0xF0) ? 500 : ((500.0 * 300.0) / 360.0); + if (bpb_bps == 512) max_spt = (bit_rate_300 == 500) ? 21 : 17; + temp_rate = (bit_rate_300 == 500) ? 0 : 4; + raw_tsize[drive] = (bit_rate_300 == 500) ? 12500 : 10416; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][4] * bpb_bps)) + { + bit_rate_300 = 500; + if (bpb_bps == 512) max_spt = 21; + pclog("max_spt is %i\n", max_spt); + temp_rate = 0; + raw_tsize[drive] = 12500; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][5] * bpb_bps)) + { + bit_rate_300 = 1000; + if (bpb_bps == 512) max_spt = 41; + temp_rate = 3; + raw_tsize[drive] = 25000; + } + else /* Image too big, eject */ + { + pclog("Image is bigger than can fit on an ED floppy, ejecting...\n"); + fclose(img[drive].f); + return; + } + + if (bpb_bps == 512) /* BPB reports 512 bytes per sector, let's see if it's XDF or not */ + { + if (bit_rate_300 <= 300) /* Double-density disk, not XDF */ + { + img[drive].xdf_type = 0; + } + else + { + pclog("bpb_sectors is %i\n", bpb_sectors); + if (bpb_sectors > max_spt) + { + switch(bpb_sectors) + { + case 19: /* High density XDF @ 360 rpm */ + img[drive].xdf_type = 1; + break; + case 23: /* High density XDF @ 300 rpm */ + img[drive].xdf_type = 2; + pclog("XDF type is 2 @ %i kbps\n", bit_rate_300); + break; +#if 0 + case 24: /* High density XXDF @ 300 rpm */ + img[drive].xdf_type = 4; + break; +#endif + case 46: /* Extended density XDF */ + img[drive].xdf_type = 3; + break; +#if 0 + case 48: /* Extended density XXDF */ + img[drive].xdf_type = 5; + break; +#endif + default: /* Unknown, as we're beyond maximum sectors, get out */ + fclose(img[drive].f); + return; + } + } + else /* Amount of sectors per track that fits into a track, therefore not XDF */ + { + img[drive].xdf_type = 0; + } + } + } + else /* BPB reports sector size other than 512, can't possibly be XDF */ + { + img[drive].xdf_type = 0; + } + } + + gap2_size[drive] = (temp_rate == 3) ? 41 : 22; + pclog("GAP2 size: %i bytes\n", gap2_size[drive]); + gap3_size[drive] = gap3_sizes[temp_rate][sector_size_code(img[drive].sector_size)][img[drive].sectors]; + if (gap3_size) + { + pclog("GAP3 size: %i bytes\n", gap3_size[drive]); + } + else + { + // fclose(img[drive].f); + gap3_size[drive] = 40; + pclog("WARNING: Floppy image of unknown format was inserted into drive %c:!\n", drive + 0x41); + } + gap4_size[drive] = raw_tsize[drive] - (((pre_gap + gap2_size[drive] + pre_data + data_size + post_gap + gap3_size[drive]) * img[drive].sectors) + pre_track); + pclog("GAP4 size: %i bytes\n", gap4_size[drive]); + if (img[drive].xdf_type) + { + gap4_size[drive] = 1; + } + + if (bit_rate_300 == 250) + { + img[drive].hole = 0; + /* If drive does not support 300 RPM, the medium is to be read at a period of 26 (300 kbps). */ + img[drive].byte_period = 29; + } + else if (bit_rate_300 == 300) + { + img[drive].hole = 0; + img[drive].byte_period = 26; + } + else if (bit_rate_300 == 1000) + { + img[drive].hole = 2; + img[drive].byte_period = 8; + } + else if (bit_rate_300 < 250) + { + img[drive].hole = 0; + img[drive].byte_period = 32; + } + else + { + img[drive].hole = 1; + img[drive].byte_period = 16; + } + + if (img[drive].xdf_type) /* In case of XDF-formatted image, write-protect */ + { + writeprot[drive] = 1; + fwriteprot[drive] = writeprot[drive]; + } + + drives[drive].seek = img_seek; + drives[drive].readsector = disc_sector_readsector; + drives[drive].writesector = disc_sector_writesector; + drives[drive].readaddress = disc_sector_readaddress; + drives[drive].hole = img_hole; + drives[drive].byteperiod = img_byteperiod; + drives[drive].poll = disc_sector_poll; + drives[drive].format = disc_sector_format; + drives[drive].realtrack = img_realtrack; + drives[drive].stop = disc_sector_stop; + disc_sector_writeback[drive] = img_writeback; + + img[drive].bitcell_period_300rpm = 1000000.0 / bit_rate_300*2.0; + pclog("bit_rate_300=%g\n", bit_rate_300); + pclog("bitcell_period_300=%g\n", img[drive].bitcell_period_300rpm); +// img[drive].bitcell_period_300rpm = disc_get_bitcell_period(img[drive].rate); + pclog("img_load %d %p sectors=%i tracks=%i sides=%i sector_size=%i hole=%i\n", drive, drives, img[drive].sectors, img[drive].tracks, img[drive].sides, img[drive].sector_size, img[drive].hole); +} + +int img_hole(int drive) +{ + return img[drive].hole; +} + +int img_byteperiod(int drive) +{ + if (img[drive].byte_period == 29) + { + return (fdd_get_type(drive) & 1) ? 32 : 26; + } + return img[drive].byte_period; +} + +void img_close(int drive) +{ + if (img[drive].f) + fclose(img[drive].f); + img[drive].f = NULL; +} + +void img_seek(int drive, int track) +{ + int side; + int current_xdft = img[drive].xdf_type - 1; + + uint8_t sectors_fat, effective_sectors, sector_gap; /* Needed for XDF */ + + if (!img[drive].f) + return; + // pclog("Seek drive=%i track=%i sectors=%i sector_size=%i sides=%i\n", drive, track, img[drive].sectors,img[drive].sector_size, img[drive].sides); +// pclog(" %i %i\n", drive_type[drive], img[drive].tracks); +#ifdef MAINLINE + if ((img[drive].tracks <= 41) && fdd_doublestep_40(drive)) +#else + if ((img[drive].tracks <= 43) && fdd_doublestep_40(drive)) +#endif + track /= 2; + + // pclog("Disk seeked to track %i\n", track); + disc_track[drive] = track; + + if (img[drive].sides == 2) + { + fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size * 2, SEEK_SET); + // pclog("Seek: Current file position (H0) is: %08X\n", ftell(img[drive].f)); + fread(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + // pclog("Seek: Current file position (H1) is: %08X\n", ftell(img[drive].f)); + fread(img[drive].track_data[1], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + } + else + { + fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size, SEEK_SET); + fread(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + } + + disc_sector_reset(drive, 0); + disc_sector_reset(drive, 1); + + int sector, current_pos, sh, sr, spos, sside; + + if (img[drive].xdf_type) + { + sectors_fat = xdf_track0[current_xdft][0]; + effective_sectors = xdf_track0[current_xdft][1]; + sector_gap = xdf_track0[current_xdft][2]; + + if (!track) + { + /* Track 0, register sectors according to track 0 layout. */ + current_pos = 0; + for (sector = 0; sector < (img[drive].sectors * 2); sector++) + { + if (xdf_track0_layout[current_xdft][sector]) + { + sh = xdf_track0_layout[current_xdft][sector] & 0xFF; + sr = xdf_track0_layout[current_xdft][sector] >> 8; + spos = current_pos; + sside = 0; + if (spos > (img[drive].sectors * img[drive].sector_size)) + { + spos -= (img[drive].sectors * img[drive].sector_size); + sside = 1; + } + disc_sector_add(drive, sh, track, sh, sr, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[sside][spos]); + } + current_pos += 512; + } +#if 0 + /* Track 0, register sectors according to track 0 map. */ + /* First, the "Side 0" buffer, will also contain one sector from side 1. */ + current_pos = 0; + for (sector = 0; sector < sectors_fat; sector++) + { + if ((sector+0x81) >= 0x91) + { + disc_sector_add(drive, 0, track, 0, sector+0x85, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + } + else + { + disc_sector_add(drive, 0, track, 0, sector+0x81, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + } + current_pos += 512; + } + disc_sector_add(drive, 1, track, 1, 0x81, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + for (sector = 0; sector < 7; sector++) + { + disc_sector_add(drive, 0, track, 0, sector+1, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + } + disc_sector_add(drive, 0, track, 0, 0x9B, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + disc_sector_add(drive, 0, track, 0, 0x9C, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + disc_sector_add(drive, 0, track, 0, 0x9D, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + disc_sector_add(drive, 0, track, 0, 0x9E, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + /* Now the "Side 1" buffer, will also contain one sector from side 0. */ + current_pos = 0; + for (sector = 0; (sector < effective_sectors - 1); sector++) + { + disc_sector_add(drive, 1, track, 1, sector+0x82, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[1][current_pos]); + current_pos += 512; + } + disc_sector_add(drive, 0, track, 0, 8, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[1][current_pos]); + current_pos += 512; +#endif + } + else + { + /* Non-zero track, this will have sectors of various sizes. */ + /* First, the "Side 0" buffer. */ + current_pos = 0; + for (sector = 0; sector < xdf_spt[current_xdft]; sector++) + { + disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0], + xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2], + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += (128 << xdf_map[current_xdft][sector][2]); + } + /* Then, the "Side 1" buffer. */ + current_pos = 0; + for (sector = xdf_spt[current_xdft]; sector < (xdf_spt[current_xdft] << 1); sector++) + { + disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0], + xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2], + img[drive].bitcell_period_300rpm, + &img[drive].track_data[1][current_pos]); + current_pos += (128 << xdf_map[current_xdft][sector][2]); + } + } + } + else + { + for (side = 0; side < img[drive].sides; side++) + { + for (sector = 0; sector < img[drive].sectors; sector++) + disc_sector_add(drive, side, track, side, sector+1, img_sector_size_code(drive), + img[drive].bitcell_period_300rpm, + &img[drive].track_data[side][sector * img[drive].sector_size]); + } + } +} +void img_writeback(int drive, int track) +{ + if (!img[drive].f) + return; + + if (img[drive].xdf_type) + return; /*Should never happen*/ + + if (img[drive].sides == 2) + { + fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size * 2, SEEK_SET); + fwrite(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + fwrite(img[drive].track_data[1], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + } + else + { + fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size, SEEK_SET); + fwrite(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + } +} + diff --git a/src/disc_img.h b/src/disc_img.h new file mode 100644 index 000000000..df23c724f --- /dev/null +++ b/src/disc_img.h @@ -0,0 +1,13 @@ +void img_init(); +void img_load(int drive, char *fn); +void img_close(int drive); +void img_seek(int drive, int track); +void img_readsector(int drive, int sector, int track, int side, int density); +void img_writesector(int drive, int sector, int track, int side, int density); +void img_readaddress(int drive, int sector, int side, int density); +void img_format(int drive, int sector, int side, int density); +int img_hole(int drive); +int img_byteperiod(int drive); +void img_stop(int drive); +void img_poll(); +int img_realtrack(int track, int drive); diff --git a/src/disc_sector.c b/src/disc_sector.c new file mode 100644 index 000000000..b06b3e75d --- /dev/null +++ b/src/disc_sector.c @@ -0,0 +1,525 @@ +#include "ibm.h" +#include "disc.h" +#include "disc_sector.h" +#include "fdd.h" + +/*Handling for 'sector based' image formats (like .IMG) as opposed to 'stream based' formats (eg .FDI)*/ + +#define MAX_SECTORS 256 + +typedef struct +{ + uint8_t c, h, r, n; + int rate; + uint8_t *data; +} sector_t; + +static sector_t disc_sector_data[2][2][MAX_SECTORS]; +static int disc_sector_count[2][2]; +void (*disc_sector_writeback[2])(int drive, int track); + +enum +{ + STATE_IDLE, + STATE_READ_FIND_SECTOR, + STATE_READ_SECTOR, + STATE_READ_FIND_FIRST_SECTOR, + STATE_READ_FIRST_SECTOR, + STATE_READ_FIND_NEXT_SECTOR, + STATE_READ_NEXT_SECTOR, + STATE_WRITE_FIND_SECTOR, + STATE_WRITE_SECTOR, + STATE_READ_FIND_ADDRESS, + STATE_READ_ADDRESS, + STATE_FORMAT_FIND, + STATE_FORMAT +}; + +static int processed_bytes[2] = {0, 0}; + +static int disc_sector_state[2] = {0, 0}; +static int disc_sector_track[2] = {0, 0}; +static int disc_sector_side[2] = {0, 0}; +// static int disc_sector_drive[2] = {0, 0}; +static int disc_sector_sector[2] = {0, 0}; +static int disc_sector_n[2] = {0, 0}; +static int disc_intersector_delay[2] = {0, 0}; +static int disc_postdata_delay[2] = {0, 0}; +static int disc_track_delay[2] = {0, 0}; +static int disc_gap4_delay[2] = {0, 0}; +static uint8_t disc_sector_fill[2] = {0, 0}; +static int cur_sector[2], cur_byte[2]; +static int index_count[2]; + +int gap2 = length_gap2; +int gap3 = length_gap3; +int gap3_0 = length_gap3_0; +int gap4 = raw_track_size - (((pre_gap + length_gap2 + pre_data + data_size + post_gap + length_gap3) * no_sectors) + pre_track); +int gap4_0 = raw_track_size_0 - (((pre_gap + length_gap2 + pre_data + data_size + post_gap + length_gap3_0) * no_sectors_0) + pre_track); + +int raw_tsize[2] = {6250, 6250}; +int gap2_size[2] = {22, 22}; +int gap3_size[2] = {0, 0}; +int gap4_size[2] = {0, 0}; + +void disc_sector_reset(int drive, int side) +{ + disc_sector_count[drive][side] = 0; + + disc_intersector_delay[drive] = 0; + disc_postdata_delay[drive] = 0; + disc_track_delay[drive] = 0; + disc_gap4_delay[drive] = 0; + cur_sector[drive] = 0; + cur_byte[drive] = 0; + index_count[drive] = 0; +} + +void disc_sector_add(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n, int rate, uint8_t *data) +{ + sector_t *s = &disc_sector_data[drive][side][disc_sector_count[drive][side]]; +//pclog("disc_sector_add: drive=%i side=%i %i r=%i\n", drive, side, disc_sector_count[drive][side],r ); + if (disc_sector_count[drive][side] >= MAX_SECTORS) + return; + + s->c = c; + s->h = h; + s->r = r; + s->n = n; + s->rate = rate; + s->data = data; + + disc_sector_count[drive][side]++; +} + +static int get_bitcell_period(int drive) +{ + return (disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]].rate * 300) / fdd_getrpm(drive); +} + +void disc_sector_readsector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + pclog("disc_sector_readsector: fdc_period=%i img_period=%i rate=%i sector=%i track=%i side=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate, sector, track, side); + pclog("pre_track=%i, pre_sector=%i, gap4=%i\n", pre_track, post_gap + gap3 + pre_gap + gap2 + pre_data, gap4); + + if (sector == SECTOR_FIRST) + disc_sector_state[drive] = STATE_READ_FIND_FIRST_SECTOR; + else if (sector == SECTOR_NEXT) + disc_sector_state[drive] = STATE_READ_FIND_NEXT_SECTOR; + else + disc_sector_state[drive] = STATE_READ_FIND_SECTOR; + disc_sector_track[drive] = track; + disc_sector_side[drive] = side; + // disc_sector_drive = drive; + disc_sector_sector[drive] = sector; + disc_sector_n[drive] = sector_size; + if ((cur_sector[drive] == 0) && (cur_byte[drive] == 0) && !disc_track_delay[drive]) disc_track_delay[drive] = pre_track; + index_count[drive] = 0; + processed_bytes[drive] = 0; + // pclog("Disk poll time is: %i\n", disc_poll_time); +} + +void disc_sector_writesector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + pclog("disc_sector_writesector: fdc_period=%i img_period=%i rate=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate); + + disc_sector_state[drive] = STATE_WRITE_FIND_SECTOR; + disc_sector_track[drive] = track; + disc_sector_side[drive] = side; + // disc_sector_drive = drive; + disc_sector_sector[drive] = sector; + disc_sector_n[drive] = sector_size; + if ((cur_sector[drive] == 0) && (cur_byte[drive] == 0) && !disc_track_delay[drive]) disc_track_delay[drive] = pre_track; + index_count[drive] = 0; + processed_bytes[drive] = 0; +} + +void disc_sector_readaddress(int drive, int track, int side, int rate) +{ + pclog("disc_sector_readaddress: fdc_period=%i img_period=%i rate=%i track=%i side=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate, track, side); + + disc_sector_state[drive] = STATE_READ_FIND_ADDRESS; + disc_sector_track[drive] = track; + disc_sector_side[drive] = side; + // disc_sector_drive = drive; + if ((cur_sector[drive] == 0) && (cur_byte[drive] == 0) && !disc_track_delay[drive]) + { + disc_track_delay[drive] = pre_track; + index_count[drive] = -1; + } + else + index_count[drive] = 0; + + processed_bytes[drive] = 0; +} + +void disc_sector_format(int drive, int track, int side, int rate, uint8_t fill) +{ + disc_sector_state[drive] = STATE_FORMAT_FIND; + disc_sector_track[drive] = track; + disc_sector_side[drive] = side; + // disc_sector_drive = drive; + disc_sector_fill[drive] = fill; + index_count[drive] = 0; +} + +void disc_sector_stop(int drive) +{ + disc_sector_state[drive] = STATE_IDLE; +} + +static void index_pulse(int drive) +{ + if (disc_sector_state[drive] != STATE_IDLE) fdc_indexpulse(); +} + +static int advance_byte(int drive) +{ + /* 0 = regular byte, 1 = missing clock pulse */ + int type = 0; + + processed_bytes[drive]++; + // pclog("advance_byte(%i): %i\n", drive, processed_bytes[drive]); + if (disc_postdata_delay[drive]) + { + disc_postdata_delay[drive]--; + return type; + } + if (disc_gap4_delay[drive]) + { + disc_gap4_delay[drive]--; + return type; + } + if (disc_track_delay[drive]) + { + if ((disc_track_delay[drive] >= (pre_track - 92)) && (disc_track_delay[drive] <= (pre_track - 94))) type = 1; + if (disc_track_delay[drive] == pre_track) + { + // pclog("Track index pulse!\n"); + index_pulse(drive); + index_count[drive]++; + } + disc_track_delay[drive]--; + if (type) pclog("advance_byte(): Track sync\n"); + return type; + } + if (disc_intersector_delay[drive]) + { + if ((disc_intersector_delay[drive] >= (pre_gap + gap2_size[drive] + pre_data - 12)) && (disc_intersector_delay[drive] <= (pre_gap + gap2_size[drive] + pre_data - 14))) type = 1; + if ((disc_intersector_delay[drive] >= (pre_gap + gap2_size[drive] + pre_data - 56)) && (disc_intersector_delay[drive] <= (pre_gap + gap2_size[drive] + pre_data - 58))) type = 2; + disc_intersector_delay[drive]--; + if (type == 1) pclog("advance_byte(): Sector address sync\n"); + if (type == 2) pclog("advance_byte(): Sector sync\n"); + return type; + } + cur_byte[drive]++; + if (cur_byte[drive] >= (128 << disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]].n)) + { + cur_byte[drive] = 0; + cur_sector[drive]++; + disc_postdata_delay[drive] = post_gap + (gap3_size[drive]); + if (cur_sector[drive] >= disc_sector_count[drive][disc_sector_side[drive]]) + { + cur_sector[drive] = 0; + disc_gap4_delay[drive] = (gap4_size[drive]); + disc_track_delay[drive] = pre_track; + disc_intersector_delay[drive] = pre_gap + gap2_size[drive] + pre_data; + } + else + { + disc_gap4_delay[drive] = 0; + disc_track_delay[drive] = 0; + disc_intersector_delay[drive] = pre_gap + gap2_size[drive] + pre_data; + } + } + return type; +} + +int head_byte(int drive, int h) +{ + return (fdd_get_head(drive) << 2) | h; +} + +int disc_sector_poll(int drive) +{ + sector_t *s; + int data; + + int do_period = 0; + + int sector_type = 0; + + if (cur_sector[drive] >= disc_sector_count[drive][disc_sector_side[drive]]) + cur_sector[drive] = 0; + if (cur_byte[drive] >= (128 << disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]].n)) + cur_byte[drive] = 0; + + /* Note: Side to read from should be chosen from FDC head select rather than from the sector ID. */ + s = &disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]]; + + if (fdd_stepping_motor_on[drive]) + { + /* If stepping motor is on, turn off data separator. */ + sector_type = advance_byte(drive); + do_period = 1; + + do_period = do_period ? ((sector_type > 0) ? 2 : 1) : 0; + return do_period; + } + + switch (disc_sector_state[drive]) + { + case STATE_IDLE: + sector_type = advance_byte(drive); + do_period = 1; + break; + + case STATE_READ_FIND_SECTOR: +/* pclog("STATE_READ_FIND_SECTOR: cur_sector=%i cur_byte=%i sector=%i,%i side=%i,%i track=%i,%i period=%i,%i\n", + cur_sector[drive], cur_byte[drive], + disc_sector_sector[drive], s->r, + disc_sector_side[drive], s->h, + disc_sector_track[drive], s->c, + fdc_get_bitcell_period(), get_bitcell_period(drive));*/ + if (index_count[drive] > 1) + { +// pclog("Find sector not found\n"); + pclog("READ: Sector (%i %i %i %i) not found (last: %i %i %i) (period=%i,%i)\n", s->c, s->h, s->r, s->n, disc_sector_track, disc_sector_side, disc_sector_sector, fdc_get_bitcell_period(), get_bitcell_period(drive)); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } +/* pclog("%i %i %i %i %i\n", cur_byte[drive], disc_sector_track[drive] != s->c, + disc_sector_side[drive] != s->h, + disc_sector_sector[drive] != s->r, + fdc_get_bitcell_period() != get_bitcell_period(drive));*/ + if (cur_byte[drive] || disc_sector_track[drive] != s->c || + disc_sector_side[drive] != s->h || + disc_sector_sector[drive] != s->r || + disc_sector_n[drive] != s->n || + (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + !fdd_can_read_medium(drive ^ fdd_swap) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_READ_SECTOR; + case STATE_READ_SECTOR: +// pclog("STATE_READ_SECTOR: cur_byte=%i %i\n", cur_byte[drive], disc_intersector_delay[drive]); + if (fdc_data(s->data[cur_byte[drive]])) + { +// pclog("fdc_data failed\n"); + return 0; + } + sector_type = advance_byte(drive); + do_period = 1; + if (!cur_byte[drive]) + { + disc_sector_state[drive] = STATE_IDLE; + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + } + break; + + case STATE_READ_FIND_FIRST_SECTOR: + if (!fdd_can_read_medium(drive ^ fdd_swap)) + { + pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (cur_byte[drive] || !index_count[drive] || fdc_get_bitcell_period() != get_bitcell_period(drive) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_READ_FIRST_SECTOR; + case STATE_READ_FIRST_SECTOR: + if (fdc_data(s->data[cur_byte[drive]])) + return 0; + sector_type = advance_byte(drive); + do_period = 1; + if (!cur_byte[drive]) + { + disc_sector_state[drive] = STATE_IDLE; + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + } + break; + + case STATE_READ_FIND_NEXT_SECTOR: + if (!fdd_can_read_medium(drive ^ fdd_swap)) + { + pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (index_count[drive] > 0) + { + pclog("Find next sector hit end of track\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (cur_byte[drive] || (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_READ_NEXT_SECTOR; + case STATE_READ_NEXT_SECTOR: + if (fdc_data(s->data[cur_byte[drive]])) + break; + sector_type = advance_byte(drive); + do_period = 1; + if (!cur_byte[drive]) + { + disc_sector_state[drive] = STATE_IDLE; + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + } + break; + + case STATE_WRITE_FIND_SECTOR: + if (!fdd_can_read_medium(drive ^ fdd_swap)) + { + // pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (writeprot[drive] || swwp) + { + fdc_writeprotect(); + return 0; + } + if (index_count[drive] > 1) + { + // pclog("Write find sector not found\n"); + pclog("WRITE: Sector (%i %i %i %i) not found\n", s->c, s->h, s->r, s->n); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (cur_byte[drive] || disc_sector_track[drive] != s->c || + disc_sector_side[drive] != s->h || + disc_sector_sector[drive] != s->r || + disc_sector_n[drive] != s->n || + (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_WRITE_SECTOR; + case STATE_WRITE_SECTOR: + data = fdc_getdata(cur_byte[drive] == ((128 << s->n) - 1)); + if (data == -1) + break; + if (!disable_write) s->data[cur_byte[drive]] = data; + sector_type = advance_byte(drive); + do_period = 1; + if (!cur_byte[drive]) + { + disc_sector_state[drive] = STATE_IDLE; + if (!disable_write) disc_sector_writeback[drive](drive, disc_sector_track[drive]); + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + } + break; + + case STATE_READ_FIND_ADDRESS: + if (!fdd_can_read_medium(drive ^ fdd_swap)) + { + pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (index_count[drive] > 0) + { + pclog("Find next sector hit end of track\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (cur_byte[drive] || (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_READ_ADDRESS; + case STATE_READ_ADDRESS: + fdc_sectorid(s->c, s->h, s->r, s->n, 0, 0); + disc_sector_state[drive] = STATE_IDLE; + break; + + case STATE_FORMAT_FIND: + if (writeprot[drive] || swwp) + { + fdc_writeprotect(); + return 0; + } + if (!index_count[drive] || (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + sector_type = advance_byte(drive); + do_period = 1; + break; + } + if (!(fdd_can_read_medium(drive ^ fdd_swap))) + { + pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (fdc_get_bitcell_period() != get_bitcell_period(drive)) + { + pclog("Bitcell period mismatch\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + disc_sector_state[drive] = STATE_FORMAT; + case STATE_FORMAT: + if (!disc_intersector_delay[drive] && fdc_get_bitcell_period() == get_bitcell_period(drive) && !disable_write) + s->data[cur_byte[drive]] = disc_sector_fill[drive]; + sector_type = advance_byte(drive); + do_period = 1; + if (index_count[drive] == 2) + { + if (!disable_write) disc_sector_writeback[drive](drive, disc_sector_track[drive]); + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + disc_sector_state[drive] = STATE_IDLE; + } + break; + } + + // if (do_period) pclog("disc_sector_poll(%i) = %i\n", drive, sector_type); + do_period = do_period ? ((sector_type > 0) ? 2 : 1) : 0; + return do_period; +} + diff --git a/src/disc_sector.h b/src/disc_sector.h new file mode 100644 index 000000000..b95b7e129 --- /dev/null +++ b/src/disc_sector.h @@ -0,0 +1,43 @@ +void disc_sector_reset(int drive, int side); +void disc_sector_add(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n, int rate, uint8_t *data); +void disc_sector_readsector(int drive, int sector, int track, int side, int density, int sector_size); +void disc_sector_writesector(int drive, int sector, int track, int side, int density, int sector_size); +void disc_sector_readaddress(int drive, int sector, int side, int density); +void disc_sector_format(int drive, int sector, int side, int density, uint8_t fill); +void disc_sector_stop(int drive); +int disc_sector_poll(int drive); +void disc_sector_stop(int drive); + +#define length_gap0 80 +#define length_gap1 50 +#define length_sync 12 +#define length_am 4 +#define length_crc 2 +#define length_gap2 22 +#define length_gap3 84 // 88 +#define length_gap3_0 108 +#define no_sectors 15 // 8 +#define no_sectors_0 18 +#define raw_track_size 10416 // 6250 +#define raw_track_size_0 12500 + +#define IBM +#define MFM +#ifdef IBM +#define pre_gap1 length_gap0 + length_sync + length_am +#else +#define pre_gap1 0 +#endif + +#define pre_track pre_gap1 + length_gap1 +#define pre_gap length_sync + length_am + 4 + length_crc // 22 +#define pre_data length_sync + length_am // 16 +#define data_size 512 +#define post_gap length_crc + +extern int raw_tsize[2]; +extern int gap2_size[2]; +extern int gap3_size[2]; +extern int gap4_size[2]; + +extern void (*disc_sector_writeback[2])(int drive, int track); diff --git a/src/dma.c b/src/dma.c new file mode 100644 index 000000000..c05e6d94e --- /dev/null +++ b/src/dma.c @@ -0,0 +1,389 @@ +#include "ibm.h" + +#include "dma.h" +#include "fdc.h" +#include "io.h" +#include "mem.h" +#include "video.h" + +static uint8_t dmaregs[16]; +static int dmaon[4]; +static uint8_t dma16regs[16]; +static int dma16on[4]; +static uint8_t dmapages[16]; + +void dma_reset() +{ + int c; + dma.wp = 0; + for (c = 0; c < 16; c++) + dmaregs[c] = 0; + for (c = 0; c < 4; c++) + { + dma.mode[c] = 0; + dma.ac[c] = 0; + dma.cc[c] = 0; + dma.ab[c] = 0; + dma.cb[c] = 0; + } + dma.m = 0; + + dma16.wp = 0; + for (c = 0; c < 16; c++) + dma16regs[c] = 0; + for (c = 0; c < 4; c++) + { + dma16.mode[c] = 0; + dma16.ac[c] = 0; + dma16.cc[c] = 0; + dma16.ab[c] = 0; + dma16.cb[c] = 0; + } + dma16.m = 0; +} + +uint8_t dma_read(uint16_t addr, void *priv) +{ + uint8_t temp; +// printf("Read DMA %04X %04X:%04X %i %02X\n",addr,CS,pc, pic_intpending, pic.pend); + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma.wp ^= 1; + if (dma.wp) + return dma.ac[(addr >> 1) & 3] & 0xff; + return dma.ac[(addr >> 1) & 3] >> 8; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma.wp ^= 1; + if (dma.wp) temp = dma.cc[(addr >> 1) & 3] & 0xff; + else temp = dma.cc[(addr >> 1) & 3] >> 8; + return temp; + + case 8: /*Status register*/ + temp = dma.stat; + dma.stat = 0; + return temp; + + case 0xd: + return 0; + } +// printf("Bad DMA read %04X %04X:%04X\n",addr,CS,pc); + return dmaregs[addr & 0xf]; +} + +void dma_write(uint16_t addr, uint8_t val, void *priv) +{ +// printf("Write DMA %04X %02X %04X:%04X\n",addr,val,CS,pc); + dmaregs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma.wp ^= 1; + if (dma.wp) dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xff00) | val; + else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8); + dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3]; + dmaon[(addr >> 1) & 3] = 1; + return; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma.wp ^= 1; + if (dma.wp) dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0xff00) | val; + else dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); + dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3]; + dmaon[(addr >> 1) & 3] = 1; + return; + + case 8: /*Control register*/ + dma.command = val; + return; + + case 0xa: /*Mask*/ + if (val & 4) dma.m |= (1 << (val & 3)); + else dma.m &= ~(1 << (val & 3)); + return; + + case 0xb: /*Mode*/ + dma.mode[val & 3] = val; + return; + + case 0xc: /*Clear FF*/ + dma.wp = 0; + return; + + case 0xd: /*Master clear*/ + dma.wp = 0; + dma.m = 0xf; + return; + + case 0xf: /*Mask write*/ + dma.m = val & 0xf; + return; + } +} + +uint8_t dma16_read(uint16_t addr, void *priv) +{ + uint8_t temp; +// printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc); + addr >>= 1; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma16.wp ^= 1; + if (dma16.wp) + return dma16.ac[(addr >> 1) & 3] & 0xff; + return dma16.ac[(addr >> 1) & 3] >> 8; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma16.wp ^= 1; + if (dma16.wp) temp = dma16.cc[(addr >> 1) & 3] & 0xff; + else temp = dma16.cc[(addr >> 1) & 3] >> 8; + return temp; + + case 8: /*Status register*/ + temp = dma16.stat; + dma16.stat = 0; + return temp; + } + return dma16regs[addr & 0xf]; +} + +void dma16_write(uint16_t addr, uint8_t val, void *priv) +{ +// printf("Write dma16 %04X %02X %04X:%04X\n",addr,val,CS,pc); + addr >>= 1; + dma16regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma16.wp ^= 1; + if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00) | val; + else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8); + dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3]; + dma16on[(addr >> 1) & 3] = 1; + return; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma16.wp ^= 1; + if (dma16.wp) dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0xff00) | val; + else dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); + dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3]; + dma16on[(addr >> 1) & 3] = 1; + return; + + case 8: /*Control register*/ + return; + + case 0xa: /*Mask*/ + if (val & 4) dma16.m |= (1 << (val & 3)); + else dma16.m &= ~(1 << (val & 3)); + return; + + case 0xb: /*Mode*/ + dma16.mode[val & 3] = val; + return; + + case 0xc: /*Clear FF*/ + dma16.wp = 0; + return; + + case 0xd: /*Master clear*/ + dma16.wp = 0; + dma16.m = 0xf; + return; + + case 0xf: /*Mask write*/ + dma16.m = val&0xf; + return; + } +} + + +void dma_page_write(uint16_t addr, uint8_t val, void *priv) +{ + dmapages[addr & 0xf] = val; + switch (addr & 0xf) + { + case 1: + dma.page[2] = (AT) ? val : val & 0xf; + break; + case 2: + dma.page[3] = (AT) ? val : val & 0xf; + break; + case 3: + dma.page[1] = (AT) ? val : val & 0xf; + break; + case 0xb: + dma16.page[1] = val; + break; + } +} + +uint8_t dma_page_read(uint16_t addr, void *priv) +{ + return dmapages[addr & 0xf]; +} + +void dma_init() +{ + io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL, NULL); + io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); +} + +void dma16_init() +{ + io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL, NULL); + io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); +} + + +uint8_t _dma_read(uint32_t addr) +{ + return mem_readb_phys(addr); +} + +void _dma_write(uint32_t addr, uint8_t val) +{ + mem_writeb_phys(addr, val); + mem_invalidate_range(addr, addr); +} + +int dma_channel_read(int channel) +{ + uint16_t temp; + int tc = 0; + + if (dma.command & 0x04) + return DMA_NODATA; + + if (!AT) + refreshread(); + + if (channel < 4) + { + if (dma.m & (1 << channel)) + return DMA_NODATA; + if ((dma.mode[channel] & 0xC) != 8) + return DMA_NODATA; + + temp = _dma_read(dma.ac[channel] + (dma.page[channel] << 16)); //ram[(dma.ac[2]+(dma.page[2]<<16))&rammask]; + + if (dma.mode[channel] & 0x20) dma.ac[channel]--; + else dma.ac[channel]++; + dma.cc[channel]--; + if (dma.cc[channel] < 0) + { + tc = 1; + if (dma.mode[channel] & 0x10) /*Auto-init*/ + { + dma.cc[channel] = dma.cb[channel]; + dma.ac[channel] = dma.ab[channel]; + } + else + dma.m |= (1 << channel); + dma.stat |= (1 << channel); + } + + if (tc) + return temp | DMA_OVER; + return temp; + } + else + { + channel &= 3; + if (dma16.m & (1 << channel)) + return DMA_NODATA; + if ((dma16.mode[channel] & 0xC) != 8) + return DMA_NODATA; + + temp = _dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16)) | + (_dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1) << 8); + + if (dma16.mode[channel] & 0x20) dma16.ac[channel]--; + else dma16.ac[channel]++; + dma16.cc[channel]--; + if (dma16.cc[channel] < 0) + { + tc = 1; + if (dma16.mode[channel] & 0x10) /*Auto-init*/ + { + dma16.cc[channel] = dma16.cb[channel]; + dma16.ac[channel] = dma16.ab[channel]; + } + else + dma16.m |= (1 << channel); + dma16.stat |= (1 << channel); + } + + if (tc) + return temp | DMA_OVER; + return temp; + } +} + +int dma_channel_write(int channel, uint16_t val) +{ + if (dma.command & 0x04) + return DMA_NODATA; + + if (!AT) + refreshread(); + + if (channel < 4) + { + if (dma.m & (1 << channel)) + return DMA_NODATA; + if ((dma.mode[channel] & 0xC) != 4) + return DMA_NODATA; + + _dma_write(dma.ac[channel] + (dma.page[channel] << 16), val); + + if (dma.mode[channel]&0x20) dma.ac[channel]--; + else dma.ac[channel]++; + dma.cc[channel]--; + if (dma.cc[channel] < 0) + { + if (dma.mode[channel] & 0x10) /*Auto-init*/ + { + dma.cc[channel] = dma.cb[channel]; + dma.ac[channel] = dma.ab[channel]; + } + else + dma.m |= (1 << channel); + dma.stat |= (1 << channel); + } + + if (dma.m & (1 << channel)) + return DMA_OVER; + } + else + { + channel &= 3; + if (dma16.m & (1 << channel)) + return DMA_NODATA; + if ((dma16.mode[channel] & 0xC) != 4) + return DMA_NODATA; + + _dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16), val); + _dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1, val >> 8); + + if (dma16.mode[channel]&0x20) dma16.ac[channel]--; + else dma16.ac[channel]++; + dma16.cc[channel]--; + if (dma16.cc[channel] < 0) + { + if (dma16.mode[channel] & 0x10) /*Auto-init*/ + { + dma16.cc[channel] = dma16.cb[channel] + 1; + dma16.ac[channel] = dma16.ab[channel]; + } + dma16.m |= (1 << channel); + dma16.stat |= (1 << channel); + } + + if (dma.m & (1 << channel)) + return DMA_OVER; + } + return 0; +} diff --git a/src/dma.h b/src/dma.h new file mode 100644 index 000000000..451d8d6d3 --- /dev/null +++ b/src/dma.h @@ -0,0 +1,16 @@ +void dma_init(); +void dma16_init(); +void dma_reset(); + +#define DMA_NODATA -1 +#define DMA_OVER 0x10000 + +void readdma0(); +int readdma1(); +uint8_t readdma2(); +int readdma3(); + +void writedma2(uint8_t temp); + +int dma_channel_read(int channel); +int dma_channel_write(int channel, uint16_t val); diff --git a/src/dosbox/dbopl.cpp b/src/dosbox/dbopl.cpp new file mode 100644 index 000000000..b8c065453 --- /dev/null +++ b/src/dosbox/dbopl.cpp @@ -0,0 +1,1521 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * 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. + */ + +/* + DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator. + Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2 + Except for the table generation it's all integer math + Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms + The generation was based on the MAME implementation but tried to have it use less memory and be faster in general + MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times + + //TODO Don't delay first operator 1 sample in opl3 mode + //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter + //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? + //TODO Check if having the same accuracy in all frequency multipliers sounds better or not + + //DUNNO Keyon in 4op, switch to 2op without keyoff. +*/ + +/* $Id: dbopl.cpp,v 1.10 2009-06-10 19:54:51 harekiet Exp $ */ + +#include +#include +#include +//#include "dosbox.h" +#include "dbopl.h" + + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +namespace DBOPL { + +#define OPLRATE ((double)(14318180.0 / 288.0)) +#define TREMOLO_TABLE 52 + +//Try to use most precision for frequencies +//Else try to keep different waves in synch +//#define WAVE_PRECISION 1 +#ifndef WAVE_PRECISION +//Wave bits available in the top of the 32bit range +//Original adlib uses 10.10, we use 10.22 +#define WAVE_BITS 10 +#else +//Need some extra bits at the top to have room for octaves and frequency multiplier +//We support to 8 times lower rate +//128 * 15 * 8 = 15350, 2^13.9, so need 14 bits +#define WAVE_BITS 14 +#endif +#define WAVE_SH ( 32 - WAVE_BITS ) +#define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 ) + +//Use the same accuracy as the waves +#define LFO_SH ( WAVE_SH - 10 ) +//LFO is controlled by our tremolo 256 sample limit +#define LFO_MAX ( 256 << ( LFO_SH ) ) + + +//Maximum amount of attenuation bits +//Envelope goes to 511, 9 bits +#if (DBOPL_WAVE == WAVE_TABLEMUL ) +//Uses the value directly +#define ENV_BITS ( 9 ) +#else +//Add 3 bits here for more accuracy and would have to be shifted up either way +#define ENV_BITS ( 9 ) +#endif +//Limits of the envelope with those bits and when the envelope goes silent +#define ENV_MIN 0 +#define ENV_EXTRA ( ENV_BITS - 9 ) +#define ENV_MAX ( 511 << ENV_EXTRA ) +#define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) ) +#define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT ) + +//Attack/decay/release rate counter shift +#define RATE_SH 24 +#define RATE_MASK ( ( 1 << RATE_SH ) - 1 ) +//Has to fit within 16bit lookuptable +#define MUL_SH 16 + +//Check some ranges +#if ENV_EXTRA > 3 +#error Too many envelope bits +#endif + + +//How much to substract from the base value for the final attenuation +static const Bit8u KslCreateTable[16] = { + //0 will always be be lower than 7 * 8 + 64, 32, 24, 19, + 16, 12, 11, 10, + 8, 6, 5, 4, + 3, 2, 1, 0, +}; + +#define M(_X_) ((Bit8u)( (_X_) * 2)) +static const Bit8u FreqCreateTable[16] = { + M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ), + M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15) +}; +#undef M + +//We're not including the highest attack rate, that gets a special value +static const Bit8u AttackSamplesTable[13] = { + 69, 55, 46, 40, + 35, 29, 23, 20, + 19, 15, 11, 10, + 9 +}; +//On a real opl these values take 8 samples to reach and are based upon larger tables +static const Bit8u EnvelopeIncreaseTable[13] = { + 4, 5, 6, 7, + 8, 10, 12, 14, + 16, 20, 24, 28, + 32, +}; + +#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) +static Bit16u ExpTable[ 256 ]; +#endif + +#if ( DBOPL_WAVE == WAVE_HANDLER ) +//PI table used by WAVEHANDLER +static Bit16u SinTable[ 512 ]; +#endif + +#if ( DBOPL_WAVE > WAVE_HANDLER ) +//Layout of the waveform table in 512 entry intervals +//With overlapping waves we reduce the table to half it's size + +// | |//\\|____|WAV7|//__|/\ |____|/\/\| +// |\\//| | |WAV7| | \/| | | +// |06 |0126|17 |7 |3 |4 |4 5 |5 | + +//6 is just 0 shifted and masked + +static Bit16s WaveTable[ 8 * 512 ]; +//Distance into WaveTable the wave starts +static const Bit16u WaveBaseTable[8] = { + 0x000, 0x200, 0x200, 0x800, + 0xa00, 0xc00, 0x100, 0x400, + +}; +//Mask the counter with this +static const Bit16u WaveMaskTable[8] = { + 1023, 1023, 511, 511, + 1023, 1023, 512, 1023, +}; + +//Where to start the counter on at keyon +static const Bit16u WaveStartTable[8] = { + 512, 0, 0, 0, + 0, 512, 512, 256, +}; +#endif + +#if ( DBOPL_WAVE == WAVE_TABLEMUL ) +static Bit16u MulTable[ 384 ]; +#endif + +static Bit8u KslTable[ 8 * 16 ]; +static Bit8u TremoloTable[ TREMOLO_TABLE ]; +//Start of a channel behind the chip struct start +static Bit16u ChanOffsetTable[32]; +//Start of an operator behind the chip struct start +static Bit16u OpOffsetTable[64]; + +//The lower bits are the shift of the operator vibrato value +//The highest bit is right shifted to generate -1 or 0 for negation +//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0 +static const Bit8s VibratoTable[ 8 ] = { + 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, + 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 +}; + +//Shift strength for the ksl value determined by ksl strength +static const Bit8u KslShiftTable[4] = { + 31,1,2,0 +}; + +//Generate a table index and table shift value using input value from a selected rate +static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) { + if ( val < 13 * 4 ) { //Rate 0 - 12 + shift = 12 - ( val >> 2 ); + index = val & 3; + } else if ( val < 15 * 4 ) { //rate 13 - 14 + shift = 0; + index = val - 12 * 4; + } else { //rate 15 and up + shift = 0; + index = 12; + } +} + +#if ( DBOPL_WAVE == WAVE_HANDLER ) +/* + Generate the different waveforms out of the sine/exponetial table using handlers +*/ +static inline Bits MakeVolume( Bitu wave, Bitu volume ) { + Bitu total = wave + volume; + Bitu index = total & 0xff; + Bitu sig = ExpTable[ index ]; + Bitu exp = total >> 8; +#if 0 + //Check if we overflow the 31 shift limit + if ( exp >= 32 ) { + LOG_MSG( "WTF %d %d", total, exp ); + } +#endif + return (sig >> exp); +}; + +static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) { + Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 + Bitu wave = SinTable[i & 511]; + return (MakeVolume( wave, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) { + Bit32u wave = SinTable[i & 511]; + wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) { + Bitu wave = SinTable[i & 511]; + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) { + Bitu wave = SinTable[i & 255]; + wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 ); + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) { + //Twice as fast + i <<= 1; + Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 + Bitu wave = SinTable[i & 511]; + wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); + return (MakeVolume( wave, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) { + //Twice as fast + i <<= 1; + Bitu wave = SinTable[i & 511]; + wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) { + Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 + return (MakeVolume( 0, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) { + //Negative is reversed here + Bits neg = (( i >> 9) & 1) - 1; + Bitu wave = (i << 3); + //When negative the volume also runs backwards + wave = ((wave ^ neg) - neg) & 4095; + return (MakeVolume( wave, volume ) ^ neg) - neg; +} + +static const WaveHandler WaveHandlerTable[8] = { + WaveForm0, WaveForm1, WaveForm2, WaveForm3, + WaveForm4, WaveForm5, WaveForm6, WaveForm7 +}; + +#endif + +/* + Operator +*/ + +//We zero out when rate == 0 +inline void Operator::UpdateAttack( const Chip* chip ) { + Bit8u rate = reg60 >> 4; + if ( rate ) { + Bit8u val = (rate << 2) + ksr; + attackAdd = chip->attackRates[ val ]; + rateZero &= ~(1 << ATTACK); + } else { + attackAdd = 0; + rateZero |= (1 << ATTACK); + } +} +inline void Operator::UpdateDecay( const Chip* chip ) { + Bit8u rate = reg60 & 0xf; + if ( rate ) { + Bit8u val = (rate << 2) + ksr; + decayAdd = chip->linearRates[ val ]; + rateZero &= ~(1 << DECAY); + } else { + decayAdd = 0; + rateZero |= (1 << DECAY); + } +} +inline void Operator::UpdateRelease( const Chip* chip ) { + Bit8u rate = reg80 & 0xf; + if ( rate ) { + Bit8u val = (rate << 2) + ksr; + releaseAdd = chip->linearRates[ val ]; + rateZero &= ~(1 << RELEASE); + if ( !(reg20 & MASK_SUSTAIN ) ) { + rateZero &= ~( 1 << SUSTAIN ); + } + } else { + rateZero |= (1 << RELEASE); + releaseAdd = 0; + if ( !(reg20 & MASK_SUSTAIN ) ) { + rateZero |= ( 1 << SUSTAIN ); + } + } +} + +inline void Operator::UpdateAttenuation( ) { + Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff); + Bit32u tl = reg40 & 0x3f; + Bit8u kslShift = KslShiftTable[ reg40 >> 6 ]; + //Make sure the attenuation goes to the right bits + totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max + totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift; +} + +void Operator::UpdateFrequency( ) { + Bit32u freq = chanData & (( 1 << 10 ) - 1); + Bit32u block = (chanData >> 10) & 0xff; +#ifdef WAVE_PRECISION + block = 7 - block; + waveAdd = ( freq * freqMul ) >> block; +#else + waveAdd = ( freq << block ) * freqMul; +#endif + if ( reg20 & MASK_VIBRATO ) { + vibStrength = (Bit8u)(freq >> 7); + +#ifdef WAVE_PRECISION + vibrato = ( vibStrength * freqMul ) >> block; +#else + vibrato = ( vibStrength << block ) * freqMul; +#endif + } else { + vibStrength = 0; + vibrato = 0; + } +} + +void Operator::UpdateRates( const Chip* chip ) { + //Mame seems to reverse this where enabling ksr actually lowers + //the rate, but pdf manuals says otherwise? + Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff); + if ( !( reg20 & MASK_KSR ) ) { + newKsr >>= 2; + } + if ( ksr == newKsr ) + return; + ksr = newKsr; + UpdateAttack( chip ); + UpdateDecay( chip ); + UpdateRelease( chip ); +} + +INLINE Bit32s Operator::RateForward( Bit32u add ) { + rateIndex += add; + Bit32s ret = rateIndex >> RATE_SH; + rateIndex = rateIndex & RATE_MASK; + return ret; +} + +template< Operator::State yes> +Bits Operator::TemplateVolume( ) { + Bit32s vol = volume; + Bit32s change; + switch ( yes ) { + case OFF: + return ENV_MAX; + case ATTACK: + change = RateForward( attackAdd ); + if ( !change ) + return vol; + vol += ( (~vol) * change ) >> 3; + if ( vol < ENV_MIN ) { + volume = ENV_MIN; + rateIndex = 0; + SetState( DECAY ); + return ENV_MIN; + } + break; + case DECAY: + vol += RateForward( decayAdd ); + if ( GCC_UNLIKELY(vol >= sustainLevel) ) { + //Check if we didn't overshoot max attenuation, then just go off + if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { + volume = ENV_MAX; + SetState( OFF ); + return ENV_MAX; + } + //Continue as sustain + rateIndex = 0; + SetState( SUSTAIN ); + } + break; + case SUSTAIN: + if ( reg20 & MASK_SUSTAIN ) { + return vol; + } + //In sustain phase, but not sustaining, do regular release + case RELEASE: + vol += RateForward( releaseAdd );; + if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { + volume = ENV_MAX; + SetState( OFF ); + return ENV_MAX; + } + break; + } + volume = vol; + return vol; +} + +static const VolumeHandler VolumeHandlerTable[5] = { + &Operator::TemplateVolume< Operator::OFF >, + &Operator::TemplateVolume< Operator::RELEASE >, + &Operator::TemplateVolume< Operator::SUSTAIN >, + &Operator::TemplateVolume< Operator::DECAY >, + &Operator::TemplateVolume< Operator::ATTACK > +}; + +INLINE Bitu Operator::ForwardVolume() { + return currentLevel + (this->*volHandler)(); +} + + +INLINE Bitu Operator::ForwardWave() { + waveIndex += waveCurrent; + return waveIndex >> WAVE_SH; +} + +void Operator::Write20( const Chip* chip, Bit8u val ) { + Bit8u change = (reg20 ^ val ); + if ( !change ) + return; + reg20 = val; + //Shift the tremolo bit over the entire register, saved a branch, YES! + tremoloMask = (Bit8s)(val) >> 7; + tremoloMask &= ~(( 1 << ENV_EXTRA ) -1); + //Update specific features based on changes + if ( change & MASK_KSR ) { + UpdateRates( chip ); + } + //With sustain enable the volume doesn't change + if ( reg20 & MASK_SUSTAIN || ( !releaseAdd ) ) { + rateZero |= ( 1 << SUSTAIN ); + } else { + rateZero &= ~( 1 << SUSTAIN ); + } + //Frequency multiplier or vibrato changed + if ( change & (0xf | MASK_VIBRATO) ) { + freqMul = chip->freqMul[ val & 0xf ]; + UpdateFrequency(); + } +} + +void Operator::Write40( const Chip* /*chip*/, Bit8u val ) { + if (!(reg40 ^ val )) + return; + reg40 = val; + UpdateAttenuation( ); +} + +void Operator::Write60( const Chip* chip, Bit8u val ) { + Bit8u change = reg60 ^ val; + reg60 = val; + if ( change & 0x0f ) { + UpdateDecay( chip ); + } + if ( change & 0xf0 ) { + UpdateAttack( chip ); + } +} + +void Operator::Write80( const Chip* chip, Bit8u val ) { + Bit8u change = (reg80 ^ val ); + if ( !change ) + return; + reg80 = val; + Bit8u sustain = val >> 4; + //Turn 0xf into 0x1f + sustain |= ( sustain + 1) & 0x10; + sustainLevel = sustain << ( ENV_BITS - 5 ); + if ( change & 0x0f ) { + UpdateRelease( chip ); + } +} + +void Operator::WriteE0( const Chip* chip, Bit8u val ) { + if ( !(regE0 ^ val) ) + return; + //in opl3 mode you can always selet 7 waveforms regardless of waveformselect + Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); + regE0 = val; +#if ( DBOPL_WAVE == WAVE_HANDLER ) + waveHandler = WaveHandlerTable[ waveForm ]; +#else + waveBase = WaveTable + WaveBaseTable[ waveForm ]; + waveStart = WaveStartTable[ waveForm ] << WAVE_SH; + waveMask = WaveMaskTable[ waveForm ]; +#endif +} + +INLINE void Operator::SetState( Bit8u s ) { + state = s; + volHandler = VolumeHandlerTable[ s ]; +} + +INLINE bool Operator::Silent() const { + if ( !ENV_SILENT( totalLevel + volume ) ) + return false; + if ( !(rateZero & ( 1 << state ) ) ) + return false; + return true; +} + +INLINE void Operator::Prepare( const Chip* chip ) { + currentLevel = totalLevel + (chip->tremoloValue & tremoloMask); + waveCurrent = waveAdd; + if ( vibStrength >> chip->vibratoShift ) { + Bit32s add = vibrato >> chip->vibratoShift; + //Sign extend over the shift value + Bit32s neg = chip->vibratoSign; + //Negate the add with -1 or 0 + add = ( add ^ neg ) - neg; + waveCurrent += add; + } +} + +void Operator::KeyOn( Bit8u mask ) { + if ( !keyOn ) { + //Restart the frequency generator +#if ( DBOPL_WAVE > WAVE_HANDLER ) + waveIndex = waveStart; +#else + waveIndex = 0; +#endif + rateIndex = 0; + SetState( ATTACK ); + } + keyOn |= mask; +} + +void Operator::KeyOff( Bit8u mask ) { + keyOn &= ~mask; + if ( !keyOn ) { + if ( state != OFF ) { + SetState( RELEASE ); + } + } +} + +INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) { +#if ( DBOPL_WAVE == WAVE_HANDLER ) + return waveHandler( index, vol << ( 3 - ENV_EXTRA ) ); +#elif ( DBOPL_WAVE == WAVE_TABLEMUL ) + return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; +#elif ( DBOPL_WAVE == WAVE_TABLELOG ) + Bit32s wave = waveBase[ index & waveMask ]; + Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA ); + Bit32s sig = ExpTable[ total & 0xff ]; + Bit32u exp = total >> 8; + Bit32s neg = wave >> 16; + return ((sig ^ neg) - neg) >> exp; +#else +#error "No valid wave routine" +#endif +} + +Bits INLINE Operator::GetSample( Bits modulation ) { + Bitu vol = ForwardVolume(); + if ( ENV_SILENT( vol ) ) { + //Simply forward the wave + waveIndex += waveCurrent; + return 0; + } else { + Bitu index = ForwardWave(); + index += modulation; + return GetWave( index, vol ); + } +} + +Operator::Operator() { + chanData = 0; + freqMul = 0; + waveIndex = 0; + waveAdd = 0; + waveCurrent = 0; + keyOn = 0; + ksr = 0; + reg20 = 0; + reg40 = 0; + reg60 = 0; + reg80 = 0; + regE0 = 0; + SetState( OFF ); + rateZero = (1 << OFF); + sustainLevel = ENV_MAX; + currentLevel = ENV_MAX; + totalLevel = ENV_MAX; + volume = ENV_MAX; + releaseAdd = 0; +} + +/* + Channel +*/ + +Channel::Channel() { + old[0] = old[1] = 0; + chanData = 0; + regB0 = 0; + regC0 = 0; + maskLeft = -1; + maskRight = -1; + feedback = 31; + fourMask = 0; + synthHandler = &Channel::BlockTemplate< sm2FM >; +}; + +void Channel::SetChanData( const Chip* chip, Bit32u data ) { + Bit32u change = chanData ^ data; + chanData = data; + Op( 0 )->chanData = data; + Op( 1 )->chanData = data; + //Since a frequency update triggered this, always update frequency + Op( 0 )->UpdateFrequency(); + Op( 1 )->UpdateFrequency(); + if ( change & ( 0xff << SHIFT_KSLBASE ) ) { + Op( 0 )->UpdateAttenuation(); + Op( 1 )->UpdateAttenuation(); + } + if ( change & ( 0xff << SHIFT_KEYCODE ) ) { + Op( 0 )->UpdateRates( chip ); + Op( 1 )->UpdateRates( chip ); + } +} + +void Channel::UpdateFrequency( const Chip* chip, Bit8u fourOp ) { + //Extrace the frequency bits + Bit32u data = chanData & 0xffff; + Bit32u kslBase = KslTable[ data >> 6 ]; + Bit32u keyCode = ( data & 0x1c00) >> 9; + if ( chip->reg08 & 0x40 ) { + keyCode |= ( data & 0x100)>>8; /* notesel == 1 */ + } else { + keyCode |= ( data & 0x200)>>9; /* notesel == 0 */ + } + //Add the keycode and ksl into the highest bits of chanData + data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE ); + ( this + 0 )->SetChanData( chip, data ); + if ( fourOp & 0x3f ) { + ( this + 1 )->SetChanData( chip, data ); + } +} + +void Channel::WriteA0( const Chip* chip, Bit8u val ) { + Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; + //Don't handle writes to silent fourop channels + if ( fourOp > 0x80 ) + return; + Bit32u change = (chanData ^ val ) & 0xff; + if ( change ) { + chanData ^= change; + UpdateFrequency( chip, fourOp ); + } +} + +void Channel::WriteB0( const Chip* chip, Bit8u val ) { + Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; + //Don't handle writes to silent fourop channels + if ( fourOp > 0x80 ) + return; + Bitu change = (chanData ^ ( val << 8 ) ) & 0x1f00; + if ( change ) { + chanData ^= change; + UpdateFrequency( chip, fourOp ); + } + //Check for a change in the keyon/off state + if ( !(( val ^ regB0) & 0x20)) + return; + regB0 = val; + if ( val & 0x20 ) { + Op(0)->KeyOn( 0x1 ); + Op(1)->KeyOn( 0x1 ); + if ( fourOp & 0x3f ) { + ( this + 1 )->Op(0)->KeyOn( 1 ); + ( this + 1 )->Op(1)->KeyOn( 1 ); + } + } else { + Op(0)->KeyOff( 0x1 ); + Op(1)->KeyOff( 0x1 ); + if ( fourOp & 0x3f ) { + ( this + 1 )->Op(0)->KeyOff( 1 ); + ( this + 1 )->Op(1)->KeyOff( 1 ); + } + } +} + +void Channel::WriteC0( const Chip* chip, Bit8u val ) { + Bit8u change = val ^ regC0; + if ( !change ) + return; + regC0 = val; + feedback = ( val >> 1 ) & 7; + if ( feedback ) { + //We shift the input to the right 10 bit wave index value + feedback = 9 - feedback; + } else { + feedback = 31; + } + //Select the new synth mode + if ( chip->opl3Active ) { + //4-op mode enabled for this channel + if ( (chip->reg104 & fourMask) & 0x3f ) { + Channel* chan0, *chan1; + //Check if it's the 2nd channel in a 4-op + if ( !(fourMask & 0x80 ) ) { + chan0 = this; + chan1 = this + 1; + } else { + chan0 = this - 1; + chan1 = this; + } + + Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); + switch ( synth ) { + case 0: + chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >; + break; + case 1: + chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >; + break; + case 2: + chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >; + break; + case 3: + chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >; + break; + } + //Disable updating percussion channels + } else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) { + + //Regular dual op, am or fm + } else if ( val & 1 ) { + synthHandler = &Channel::BlockTemplate< sm3AM >; + } else { + synthHandler = &Channel::BlockTemplate< sm3FM >; + } + maskLeft = ( val & 0x10 ) ? -1 : 0; + maskRight = ( val & 0x20 ) ? -1 : 0; + //opl2 active + } else { + //Disable updating percussion channels + if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { + + //Regular dual op, am or fm + } else if ( val & 1 ) { + synthHandler = &Channel::BlockTemplate< sm2AM >; + } else { + synthHandler = &Channel::BlockTemplate< sm2FM >; + } + } +} + +void Channel::ResetC0( const Chip* chip ) { + Bit8u val = regC0; + regC0 ^= 0xff; + WriteC0( chip, val ); +}; + +template< bool opl3Mode> +INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) { + Channel* chan = this; + + //BassDrum + Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; + old[0] = old[1]; + old[1] = Op(0)->GetSample( mod ); + + //When bassdrum is in AM mode first operator is ignoed + if ( chan->regC0 & 1 ) { + mod = 0; + } else { + mod = old[0]; + } + Bit32s sample = Op(1)->GetSample( mod ); + + + //Precalculate stuff used by other outputs + Bit32u noiseBit = chip->ForwardNoise() & 0x1; + Bit32u c2 = Op(2)->ForwardWave(); + Bit32u c5 = Op(5)->ForwardWave(); + Bit32u phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00; + + //Hi-Hat + Bit32u hhVol = Op(2)->ForwardVolume(); + if ( !ENV_SILENT( hhVol ) ) { + Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 ))); + sample += Op(2)->GetWave( hhIndex, hhVol ); + } + //Snare Drum + Bit32u sdVol = Op(3)->ForwardVolume(); + if ( !ENV_SILENT( sdVol ) ) { + Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 ); + sample += Op(3)->GetWave( sdIndex, sdVol ); + } + //Tom-tom + sample += Op(4)->GetSample( 0 ); + + //Top-Cymbal + Bit32u tcVol = Op(5)->ForwardVolume(); + if ( !ENV_SILENT( tcVol ) ) { + Bit32u tcIndex = (1 + phaseBit) << 8; + sample += Op(5)->GetWave( tcIndex, tcVol ); + } + sample <<= 1; + if ( opl3Mode ) { + output[0] += sample; + output[1] += sample; + } else { + output[0] += sample; + } +} + +template +Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { + switch( mode ) { + case sm2AM: + case sm3AM: + if ( Op(0)->Silent() && Op(1)->Silent() ) { + old[0] = old[1] = 0; + return (this + 1); + } + break; + case sm2FM: + case sm3FM: + if ( Op(1)->Silent() ) { + old[0] = old[1] = 0; + return (this + 1); + } + break; + case sm3FMFM: + if ( Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm3AMFM: + if ( Op(0)->Silent() && Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm3FMAM: + if ( Op(1)->Silent() && Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm3AMAM: + if ( Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + } + //Init the operators with the the current vibrato and tremolo values + Op( 0 )->Prepare( chip ); + Op( 1 )->Prepare( chip ); + if ( mode > sm4Start ) { + Op( 2 )->Prepare( chip ); + Op( 3 )->Prepare( chip ); + } + if ( mode > sm6Start ) { + Op( 4 )->Prepare( chip ); + Op( 5 )->Prepare( chip ); + } + for ( Bitu i = 0; i < samples; i++ ) { + //Early out for percussion handlers + if ( mode == sm2Percussion ) { + GeneratePercussion( chip, output + i ); + continue; //Prevent some unitialized value bitching + } else if ( mode == sm3Percussion ) { + GeneratePercussion( chip, output + i * 2 ); + continue; //Prevent some unitialized value bitching + } + + //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise + Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; + old[0] = old[1]; + old[1] = Op(0)->GetSample( mod ); + Bit32s sample; + Bit32s out0 = old[0]; + if ( mode == sm2AM || mode == sm3AM ) { + sample = out0 + Op(1)->GetSample( 0 ); + } else if ( mode == sm2FM || mode == sm3FM ) { + sample = Op(1)->GetSample( out0 ); + } else if ( mode == sm3FMFM ) { + Bits next = Op(1)->GetSample( out0 ); + next = Op(2)->GetSample( next ); + sample = Op(3)->GetSample( next ); + } else if ( mode == sm3AMFM ) { + sample = out0; + Bits next = Op(1)->GetSample( 0 ); + next = Op(2)->GetSample( next ); + sample += Op(3)->GetSample( next ); + } else if ( mode == sm3FMAM ) { + sample = Op(1)->GetSample( out0 ); + Bits next = Op(2)->GetSample( 0 ); + sample += Op(3)->GetSample( next ); + } else if ( mode == sm3AMAM ) { + sample = out0; + Bits next = Op(1)->GetSample( 0 ); + sample += Op(2)->GetSample( next ); + sample += Op(3)->GetSample( 0 ); + } + switch( mode ) { + case sm2AM: + case sm2FM: + if (chip->is_opl3) + { + output[ i * 2 + 0 ] += sample; + output[ i * 2 + 1 ] += sample; + } + else + output[ i ] += sample; + break; + case sm3AM: + case sm3FM: + case sm3FMFM: + case sm3AMFM: + case sm3FMAM: + case sm3AMAM: + output[ i * 2 + 0 ] += sample & maskLeft; + output[ i * 2 + 1 ] += sample & maskRight; + break; + } + } + switch( mode ) { + case sm2AM: + case sm2FM: + case sm3AM: + case sm3FM: + return ( this + 1 ); + case sm3FMFM: + case sm3AMFM: + case sm3FMAM: + case sm3AMAM: + return( this + 2 ); + case sm2Percussion: + case sm3Percussion: + return( this + 3 ); + } + return 0; +} + +/* + Chip +*/ + +Chip::Chip() { + reg08 = 0; + reg04 = 0; + regBD = 0; + reg104 = 0; + opl3Active = 0; +} + +INLINE Bit32u Chip::ForwardNoise() { + noiseCounter += noiseAdd; + Bitu count = noiseCounter >> LFO_SH; + noiseCounter &= WAVE_MASK; + for ( ; count > 0; --count ) { + //Noise calculation from mame + noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) ); + noiseValue >>= 1; + } + return noiseValue; +} + +INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) { + //Current vibrato value, runs 4x slower than tremolo + vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7; + vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength; + tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength; + + //Check hom many samples there can be done before the value changes + Bit32u todo = LFO_MAX - lfoCounter; + Bit32u count = (todo + lfoAdd - 1) / lfoAdd; + if ( count > samples ) { + count = samples; + lfoCounter += count * lfoAdd; + } else { + lfoCounter += count * lfoAdd; + lfoCounter &= (LFO_MAX - 1); + //Maximum of 7 vibrato value * 4 + vibratoIndex = ( vibratoIndex + 1 ) & 31; + //Clip tremolo to the the table size + if ( tremoloIndex + 1 < TREMOLO_TABLE ) + ++tremoloIndex; + else + tremoloIndex = 0; + } + return count; +} + + +void Chip::WriteBD( Bit8u val ) { + Bit8u change = regBD ^ val; + if ( !change ) + return; + regBD = val; + //TODO could do this with shift and xor? + vibratoStrength = (val & 0x40) ? 0x00 : 0x01; + tremoloStrength = (val & 0x80) ? 0x00 : 0x02; + if ( val & 0x20 ) { + //Drum was just enabled, make sure channel 6 has the right synth + if ( change & 0x20 ) { + // if ( opl3Active ) { + if ( is_opl3 ) { + chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >; + } else { + chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >; + } + } + //Bass Drum + if ( val & 0x10 ) { + chan[6].op[0].KeyOn( 0x2 ); + chan[6].op[1].KeyOn( 0x2 ); + } else { + chan[6].op[0].KeyOff( 0x2 ); + chan[6].op[1].KeyOff( 0x2 ); + } + //Hi-Hat + if ( val & 0x1 ) { + chan[7].op[0].KeyOn( 0x2 ); + } else { + chan[7].op[0].KeyOff( 0x2 ); + } + //Snare + if ( val & 0x8 ) { + chan[7].op[1].KeyOn( 0x2 ); + } else { + chan[7].op[1].KeyOff( 0x2 ); + } + //Tom-Tom + if ( val & 0x4 ) { + chan[8].op[0].KeyOn( 0x2 ); + } else { + chan[8].op[0].KeyOff( 0x2 ); + } + //Top Cymbal + if ( val & 0x2 ) { + chan[8].op[1].KeyOn( 0x2 ); + } else { + chan[8].op[1].KeyOff( 0x2 ); + } + //Toggle keyoffs when we turn off the percussion + } else if ( change & 0x20 ) { + //Trigger a reset to setup the original synth handler + chan[6].ResetC0( this ); + chan[6].op[0].KeyOff( 0x2 ); + chan[6].op[1].KeyOff( 0x2 ); + chan[7].op[0].KeyOff( 0x2 ); + chan[7].op[1].KeyOff( 0x2 ); + chan[8].op[0].KeyOff( 0x2 ); + chan[8].op[1].KeyOff( 0x2 ); + } +} + + +#define REGOP( _FUNC_ ) \ + index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \ + if ( OpOffsetTable[ index ] ) { \ + Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] ); \ + regOp->_FUNC_( this, val ); \ + } + +#define REGCHAN( _FUNC_ ) \ + index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \ + if ( ChanOffsetTable[ index ] ) { \ + Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] ); \ + regChan->_FUNC_( this, val ); \ + } + +void Chip::WriteReg( Bit32u reg, Bit8u val ) { + Bitu index; + switch ( (reg & 0xf0) >> 4 ) { + case 0x00 >> 4: + if ( reg == 0x01 ) { + waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0; + } else if ( reg == 0x104 ) { + //Only detect changes in lowest 6 bits + if ( !((reg104 ^ val) & 0x3f) ) + return; + //Always keep the highest bit enabled, for checking > 0x80 + reg104 = 0x80 | ( val & 0x3f ); + } else if ( reg == 0x105 ) { + //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register + if ( !((opl3Active ^ val) & 1 ) ) + return; + opl3Active = ( val & 1 ) ? 0xff : 0; + //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers + for ( int i = 0; i < 18;i++ ) { + chan[i].ResetC0( this ); + } + } else if ( reg == 0x08 ) { + reg08 = val; + } + case 0x10 >> 4: + break; + case 0x20 >> 4: + case 0x30 >> 4: + REGOP( Write20 ); + break; + case 0x40 >> 4: + case 0x50 >> 4: + REGOP( Write40 ); + break; + case 0x60 >> 4: + case 0x70 >> 4: + REGOP( Write60 ); + break; + case 0x80 >> 4: + case 0x90 >> 4: + REGOP( Write80 ); + break; + case 0xa0 >> 4: + REGCHAN( WriteA0 ); + break; + case 0xb0 >> 4: + if ( reg == 0xbd ) { + WriteBD( val ); + } else { + REGCHAN( WriteB0 ); + } + break; + case 0xc0 >> 4: + REGCHAN( WriteC0 ); + case 0xd0 >> 4: + break; + case 0xe0 >> 4: + case 0xf0 >> 4: + REGOP( WriteE0 ); + break; + } +} + + +Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) { + switch ( port & 3 ) { + case 0: + return val; + case 2: + if ( opl3Active || (val == 0x05) ) + return 0x100 | val; + else + return val; + } + return 0; +} + +void Chip::GenerateBlock2( Bitu total, Bit32s* output ) { + while ( total > 0 ) { + Bit32u samples = ForwardLFO( total ); + memset(output, 0, sizeof(Bit32s) * samples); + int count = 0; + for( Channel* ch = chan; ch < chan + 9; ) { + count++; + ch = (ch->*(ch->synthHandler))( this, samples, output ); + } + total -= samples; + output += samples; + } +} + +void Chip::GenerateBlock3( Bitu total, Bit32s* output ) { + while ( total > 0 ) { + Bit32u samples = ForwardLFO( total ); + memset(output, 0, sizeof(Bit32s) * samples *2); + int count = 0; + for( Channel* ch = chan; ch < chan + 18; ) { + count++; + ch = (ch->*(ch->synthHandler))( this, samples, output ); + } + total -= samples; + output += samples * 2; + } +} + +void Chip::Setup( Bit32u rate, int chip_is_opl3 ) { + double original = OPLRATE; +// double original = rate; + double scale = original / (double)rate; + + is_opl3 = chip_is_opl3; + + //Noise counter is run at the same precision as general waves + noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); + noiseCounter = 0; + noiseValue = 1; //Make sure it triggers the noise xor the first time + //The low frequency oscillation counter + //Every time his overflows vibrato and tremoloindex are increased + lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); + lfoCounter = 0; + vibratoIndex = 0; + tremoloIndex = 0; + + //With higher octave this gets shifted up + //-1 since the freqCreateTable = *2 +#ifdef WAVE_PRECISION + double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); + for ( int i = 0; i < 16; i++ ) { + freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] ); + } +#else + Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); + for ( int i = 0; i < 16; i++ ) { + freqMul[i] = freqScale * FreqCreateTable[ i ]; + } +#endif + + //-3 since the real envelope takes 8 steps to reach the single value we supply + for ( Bit8u i = 0; i < 76; i++ ) { + Bit8u index, shift; + EnvelopeSelect( i, index, shift ); + linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); + } + //Generate the best matching attack rate + for ( Bit8u i = 0; i < 62; i++ ) { + Bit8u index, shift; + EnvelopeSelect( i, index, shift ); + //Original amount of samples the attack would take + Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); + + Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); + Bit32s bestAdd = guessAdd; + Bit32u bestDiff = 1 << 30; + for( Bit32u passes = 0; passes < 16; passes ++ ) { + Bit32s volume = ENV_MAX; + Bit32s samples = 0; + Bit32u count = 0; + while ( volume > 0 && samples < original * 2 ) { + count += guessAdd; + Bit32s change = count >> RATE_SH; + count &= RATE_MASK; + if ( GCC_UNLIKELY(change) ) { // less than 1 % + volume += ( ~volume * change ) >> 3; + } + samples++; + + } + Bit32s diff = original - samples; + Bit32u lDiff = labs( diff ); + //Init last on first pass + if ( lDiff < bestDiff ) { + bestDiff = lDiff; + bestAdd = guessAdd; + if ( !bestDiff ) + break; + } + //Below our target + if ( diff < 0 ) { + //Better than the last time + Bit32s mul = ((original - diff) << 12) / original; + guessAdd = ((guessAdd * mul) >> 12); + guessAdd++; + } else if ( diff > 0 ) { + Bit32s mul = ((original - diff) << 12) / original; + guessAdd = (guessAdd * mul) >> 12; + guessAdd--; + } + } + attackRates[i] = bestAdd; + } + for ( Bit8u i = 62; i < 76; i++ ) { + //This should provide instant volume maximizing + attackRates[i] = 8 << RATE_SH; + } + //Setup the channels with the correct four op flags + //Channels are accessed through a table so they appear linear here + chan[ 0].fourMask = 0x00 | ( 1 << 0 ); + chan[ 1].fourMask = 0x80 | ( 1 << 0 ); + chan[ 2].fourMask = 0x00 | ( 1 << 1 ); + chan[ 3].fourMask = 0x80 | ( 1 << 1 ); + chan[ 4].fourMask = 0x00 | ( 1 << 2 ); + chan[ 5].fourMask = 0x80 | ( 1 << 2 ); + + chan[ 9].fourMask = 0x00 | ( 1 << 3 ); + chan[10].fourMask = 0x80 | ( 1 << 3 ); + chan[11].fourMask = 0x00 | ( 1 << 4 ); + chan[12].fourMask = 0x80 | ( 1 << 4 ); + chan[13].fourMask = 0x00 | ( 1 << 5 ); + chan[14].fourMask = 0x80 | ( 1 << 5 ); + + //mark the percussion channels + chan[ 6].fourMask = 0x40; + chan[ 7].fourMask = 0x40; + chan[ 8].fourMask = 0x40; + + //Clear Everything in opl3 mode + WriteReg( 0x105, 0x1 ); + for ( int i = 0; i < 512; i++ ) { + if ( i == 0x105 ) + continue; + WriteReg( i, 0xff ); + WriteReg( i, 0x0 ); + } + WriteReg( 0x105, 0x0 ); + //Clear everything in opl2 mode + for ( int i = 0; i < 255; i++ ) { + WriteReg( i, 0xff ); + WriteReg( i, 0x0 ); + } +} + +static bool doneTables = false; +void InitTables( void ) { + if ( doneTables ) + return; + doneTables = true; +#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) + //Exponential volume table, same as the real adlib + for ( int i = 0; i < 256; i++ ) { + //Save them in reverse + ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 ); + ExpTable[i] += 1024; //or remove the -1 oh well :) + //Preshift to the left once so the final volume can shift to the right + ExpTable[i] *= 2; + } +#endif +#if ( DBOPL_WAVE == WAVE_HANDLER ) + //Add 0.5 for the trunc rounding of the integer cast + //Do a PI sinetable instead of the original 0.5 PI + for ( int i = 0; i < 512; i++ ) { + SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); + } +#endif +#if ( DBOPL_WAVE == WAVE_TABLEMUL ) + //Multiplication based tables + for ( int i = 0; i < 384; i++ ) { + int s = i * 8; + //TODO maybe keep some of the precision errors of the original table? + double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH )); + MulTable[i] = (Bit16u)(val); + } + + //Sine Wave Base + for ( int i = 0; i < 512; i++ ) { + WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084); + WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ]; + } + //Exponential wave + for ( int i = 0; i < 256; i++ ) { + WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 ); + WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ]; + } +#endif +#if ( DBOPL_WAVE == WAVE_TABLELOG ) + //Sine Wave Base + for ( int i = 0; i < 512; i++ ) { + WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); + WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i]; + } + //Exponential wave + for ( int i = 0; i < 256; i++ ) { + WaveTable[ 0x700 + i ] = i * 8; + WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; + } +#endif + + // | |//\\|____|WAV7|//__|/\ |____|/\/\| + // |\\//| | |WAV7| | \/| | | + // |06 |0126|27 |7 |3 |4 |4 5 |5 | + +#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) + for ( int i = 0; i < 256; i++ ) { + //Fill silence gaps + WaveTable[ 0x400 + i ] = WaveTable[0]; + WaveTable[ 0x500 + i ] = WaveTable[0]; + WaveTable[ 0x900 + i ] = WaveTable[0]; + WaveTable[ 0xc00 + i ] = WaveTable[0]; + WaveTable[ 0xd00 + i ] = WaveTable[0]; + //Replicate sines in other pieces + WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ]; + //double speed sines + WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ]; + WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ]; + WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ]; + WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ]; + } +#endif + + //Create the ksl table + for ( int oct = 0; oct < 8; oct++ ) { + int base = oct * 8; + for ( int i = 0; i < 16; i++ ) { + int val = base - KslCreateTable[i]; + if ( val < 0 ) + val = 0; + //*4 for the final range to match attenuation range + KslTable[ oct * 16 + i ] = val * 4; + } + } + //Create the Tremolo table, just increase and decrease a triangle wave + for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) { + Bit8u val = i << ENV_EXTRA; + TremoloTable[i] = val; + TremoloTable[TREMOLO_TABLE - 1 - i] = val; + } + //Create a table with offsets of the channels from the start of the chip + DBOPL::Chip* chip = 0; + for ( Bitu i = 0; i < 32; i++ ) { + Bitu index = i & 0xf; + if ( index >= 9 ) { + ChanOffsetTable[i] = 0; + continue; + } + //Make sure the four op channels follow eachother + if ( index < 6 ) { + index = (index % 3) * 2 + ( index / 3 ); + } + //Add back the bits for highest ones + if ( i >= 16 ) + index += 9; + intptr_t blah = reinterpret_cast( &(chip->chan[ index ]) ); + ChanOffsetTable[i] = blah; + } + //Same for operators + for ( Bitu i = 0; i < 64; i++ ) { + if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { + OpOffsetTable[i] = 0; + continue; + } + Bitu chNum = (i / 8) * 3 + (i % 8) % 3; + //Make sure we use 16 and up for the 2nd range to match the chanoffset gap + if ( chNum >= 12 ) + chNum += 16 - 12; + Bitu opNum = ( i % 8 ) / 3; + DBOPL::Channel* chan = 0; + intptr_t blah = reinterpret_cast( &(chan->op[opNum]) ); + OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah; + } +#if 0 + //Stupid checks if table's are correct + for ( Bitu i = 0; i < 18; i++ ) { + Bit32u find = (Bit16u)( &(chip->chan[ i ]) ); + for ( Bitu c = 0; c < 32; c++ ) { + if ( ChanOffsetTable[c] == find ) { + find = 0; + break; + } + } + if ( find ) { + find = find; + } + } + for ( Bitu i = 0; i < 36; i++ ) { + Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) ); + for ( Bitu c = 0; c < 64; c++ ) { + if ( OpOffsetTable[c] == find ) { + find = 0; + break; + } + } + if ( find ) { + find = find; + } + } +#endif +} + +/*Bit32u Handler::WriteAddr( Bit32u port, Bit8u val ) { + return chip.WriteAddr( port, val ); + +} +void Handler::WriteReg( Bit32u addr, Bit8u val ) { + chip.WriteReg( addr, val ); +} + +void Handler::Generate( MixerChannel* chan, Bitu samples ) { + Bit32s buffer[ 512 * 2 ]; + if ( GCC_UNLIKELY(samples > 512) ) + samples = 512; + if ( !chip.opl3Active ) { + chip.GenerateBlock2( samples, buffer ); + chan->AddSamples_m32( samples, buffer ); + } else { + chip.GenerateBlock3( samples, buffer ); + chan->AddSamples_s32( samples, buffer ); + } +} + +void Handler::Init( Bitu rate ) { + InitTables(); + chip.Setup( rate ); +}*/ + + +}; //Namespace DBOPL + diff --git a/src/dosbox/dbopl.h b/src/dosbox/dbopl.h new file mode 100644 index 000000000..b798ce321 --- /dev/null +++ b/src/dosbox/dbopl.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * 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 "adlib.h" +//#include "dosbox.h" +#include +typedef signed int Bits; +typedef unsigned int Bitu; +typedef int8_t Bit8s; +typedef uint8_t Bit8u; +typedef int16_t Bit16s; +typedef uint16_t Bit16u; +typedef int32_t Bit32s; +typedef uint32_t Bit32u; + +#define INLINE inline + +#define GCC_UNLIKELY(x) (x) + +//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume +#define WAVE_HANDLER 10 +//Use a logarithmic wavetable with an exponential table for volume +#define WAVE_TABLELOG 11 +//Use a linear wavetable with a multiply table for volume +#define WAVE_TABLEMUL 12 + +//Select the type of wave generator routine +#define DBOPL_WAVE WAVE_TABLEMUL + +namespace DBOPL { + +struct Chip; +struct Operator; +struct Channel; + +#if (DBOPL_WAVE == WAVE_HANDLER) +typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); +#endif + +typedef Bits ( DBOPL::Operator::*VolumeHandler) ( ); +typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output ); + +//Different synth modes that can generate blocks of data +typedef enum { + sm2AM, + sm2FM, + sm3AM, + sm3FM, + sm4Start, + sm3FMFM, + sm3AMFM, + sm3FMAM, + sm3AMAM, + sm6Start, + sm2Percussion, + sm3Percussion, +} SynthMode; + +//Shifts for the values contained in chandata variable +enum { + SHIFT_KSLBASE = 16, + SHIFT_KEYCODE = 24, +}; + +struct Operator { +public: + //Masks for operator 20 values + enum { + MASK_KSR = 0x10, + MASK_SUSTAIN = 0x20, + MASK_VIBRATO = 0x40, + MASK_TREMOLO = 0x80, + }; + + typedef enum { + OFF, + RELEASE, + SUSTAIN, + DECAY, + ATTACK, + } State; + + VolumeHandler volHandler; + +#if (DBOPL_WAVE == WAVE_HANDLER) + WaveHandler waveHandler; //Routine that generate a wave +#else + Bit16s* waveBase; + Bit32u waveMask; + Bit32u waveStart; +#endif + Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index + Bit32u waveAdd; //The base frequency without vibrato + Bit32u waveCurrent; //waveAdd + vibratao + + Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this + Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove? + Bit32u vibrato; //Scaled up vibrato strength + Bit32s sustainLevel; //When stopping at sustain level stop here + Bit32s totalLevel; //totalLevel is added to every generated volume + Bit32u currentLevel; //totalLevel + tremolo + Bit32s volume; //The currently active volume + + Bit32u attackAdd; //Timers for the different states of the envelope + Bit32u decayAdd; + Bit32u releaseAdd; + Bit32u rateIndex; //Current position of the evenlope + + Bit8u rateZero; //Bits for the different states of the envelope having no changes + Bit8u keyOn; //Bitmask of different values that can generate keyon + //Registers, also used to check for changes + Bit8u reg20, reg40, reg60, reg80, regE0; + //Active part of the envelope we're in + Bit8u state; + //0xff when tremolo is enabled + Bit8u tremoloMask; + //Strength of the vibrato + Bit8u vibStrength; + //Keep track of the calculated KSR so we can check for changes + Bit8u ksr; +private: + void SetState( Bit8u s ); + void UpdateAttack( const Chip* chip ); + void UpdateRelease( const Chip* chip ); + void UpdateDecay( const Chip* chip ); +public: + void UpdateAttenuation(); + void UpdateRates( const Chip* chip ); + void UpdateFrequency( ); + + void Write20( const Chip* chip, Bit8u val ); + void Write40( const Chip* chip, Bit8u val ); + void Write60( const Chip* chip, Bit8u val ); + void Write80( const Chip* chip, Bit8u val ); + void WriteE0( const Chip* chip, Bit8u val ); + + bool Silent() const; + void Prepare( const Chip* chip ); + + void KeyOn( Bit8u mask); + void KeyOff( Bit8u mask); + + template< State state> + Bits TemplateVolume( ); + + Bit32s RateForward( Bit32u add ); + Bitu ForwardWave(); + Bitu ForwardVolume(); + + Bits GetSample( Bits modulation ); + Bits GetWave( Bitu index, Bitu vol ); +public: + Operator(); +}; + +struct Channel { + Operator op[2]; + inline Operator* Op( Bitu index ) { + return &( ( this + (index >> 1) )->op[ index & 1 ]); + } + SynthHandler synthHandler; + Bit32u chanData; //Frequency/octave and derived values + Bit32s old[2]; //Old data for feedback + + Bit8u feedback; //Feedback shift + Bit8u regB0; //Register values to check for changes + Bit8u regC0; + //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel + Bit8u fourMask; + Bit8s maskLeft; //Sign extended values for both channel's panning + Bit8s maskRight; + + //Forward the channel data to the operators of the channel + void SetChanData( const Chip* chip, Bit32u data ); + //Change in the chandata, check for new values and if we have to forward to operators + void UpdateFrequency( const Chip* chip, Bit8u fourOp ); + void WriteA0( const Chip* chip, Bit8u val ); + void WriteB0( const Chip* chip, Bit8u val ); + void WriteC0( const Chip* chip, Bit8u val ); + void ResetC0( const Chip* chip ); + + //call this for the first channel + template< bool opl3Mode > + void GeneratePercussion( Chip* chip, Bit32s* output ); + + //Generate blocks of data in specific modes + template + Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ); + Channel(); +}; + +struct Chip { + //This is used as the base counter for vibrato and tremolo + Bit32u lfoCounter; + Bit32u lfoAdd; + + + Bit32u noiseCounter; + Bit32u noiseAdd; + Bit32u noiseValue; + + //Frequency scales for the different multiplications + Bit32u freqMul[16]; + //Rates for decay and release for rate of this chip + Bit32u linearRates[76]; + //Best match attack rates for the rate of this chip + Bit32u attackRates[76]; + + //18 channels with 2 operators each + Channel chan[18]; + + Bit8u reg104; + Bit8u reg08; + Bit8u reg04; + Bit8u regBD; + Bit8u vibratoIndex; + Bit8u tremoloIndex; + Bit8s vibratoSign; + Bit8u vibratoShift; + Bit8u tremoloValue; + Bit8u vibratoStrength; + Bit8u tremoloStrength; + //Mask for allowed wave forms + Bit8u waveFormMask; + //0 or -1 when enabled + Bit8s opl3Active; + + int is_opl3; + + //Return the maximum amount of samples before and LFO change + Bit32u ForwardLFO( Bit32u samples ); + Bit32u ForwardNoise(); + + void WriteBD( Bit8u val ); + void WriteReg(Bit32u reg, Bit8u val ); + + Bit32u WriteAddr( Bit32u port, Bit8u val ); + + void GenerateBlock2( Bitu samples, Bit32s* output ); + void GenerateBlock3( Bitu samples, Bit32s* output ); + + void Generate( Bit32u samples ); + void Setup( Bit32u r, int chip_is_opl3 ); + + Chip(); +}; + +/*struct Handler : public Adlib::Handler { + DBOPL::Chip chip; + virtual Bit32u WriteAddr( Bit32u port, Bit8u val ); + virtual void WriteReg( Bit32u addr, Bit8u val ); + virtual void Generate( MixerChannel* chan, Bitu samples ); + virtual void Init( Bitu rate ); +};*/ + +void InitTables( void ); + +}; //Namespace diff --git a/src/fdc.c b/src/fdc.c new file mode 100644 index 000000000..e01dacd45 --- /dev/null +++ b/src/fdc.c @@ -0,0 +1,1668 @@ +#include +#include +#include "ibm.h" + +#include "disc.h" +#include "dma.h" +#include "fdd.h" +#include "io.h" +#include "pic.h" +#include "timer.h" + +extern int motoron; + +extern int motor_on[2] = {0, 0}; + +static int fdc_reset_stat = 0; +/*FDC*/ +typedef struct FDC +{ + uint8_t dor,stat,command,dat,st0; + int head,track[256],sector,drive,lastdrive; + int rw_track; + int pos; + uint8_t params[256]; + uint8_t res[256]; + int pnum,ptot; + int rate; + uint8_t specify[256]; + int eot[256]; + int lock; + int perp; + uint8_t config, pretrk; + int abort; + uint8_t format_dat[256]; + int format_state; + int tc; + int written; + + int pcjr, ps1; + + int watchdog_timer; + int watchdog_count; + + int data_ready; + int inread; + + int dskchg_activelow; + int enable_3f1; + + int bitcell_period; + + int is_nsc; /* 1 = FDC is on a National Semiconductor Super I/O chip, 0 = other FDC. This is needed, + because the National Semiconductor Super I/O chips add some FDC commands. */ + int enh_mode; + int rwc[2]; + int boot_drive; + int densel_polarity; + int densel_force; + int drvrate[2]; + + int dma; + int fifo, tfifo; + int fifobufpos; + int drv2en; + uint8_t fifobuf[16]; + + int seek_params; /* Needed for relative seek. */ +} FDC; + +int skip_pulses[2] = {0, 0}; + +static FDC fdc; + +void fdc_callback(); +int timetolive; +//#define SECTORS 9 +int lastbyte=0; +uint8_t disc_3f7; + +int discmodified[2]; +int discrate[2]; + +int discint; + +#define FDC_STATE_NORMAL 0 +#define FDC_STATE_SEEK 1 + +int fdc_state = 0; + +void fdc_reset() +{ + fdc.stat=0x80; + fdc.pnum=fdc.ptot=0; + fdc.st0=0; + fdc.lock = 0; + fdc.head = 0; + fdc.abort = 0; + fdc_set_skip_pulses(0, 0); + fdc_set_skip_pulses(1, 0); + fdd_stepping_motor_on[0] = fdd_stepping_motor_on[1] = 0; + fdd_track_diff[0] = fdd_track_diff[1] = 0; +#if 0 + if (!AT) + { + fdc.rate = 2; + // fdc_update_rate(); + } +#endif + fdc_state = FDC_STATE_NORMAL; +// pclog("Reset FDC\n"); +} +int ins; + +void fdc_set_skip_pulses(int drive, int val) +{ + skip_pulses[drive] = val; + pclog("Skip pulses for drive %c: is now %i\n", 0x41 + drive, val); +} + +int fdc_skip_pulses(int drive) +{ + return (skip_pulses[drive] ? 1 : 0) || (discint < 0); +} + +void fdc_reset_fifo_buf() +{ + int i = 0; + memset(fdc.fifobuf, 0, 16); + fdc.fifobufpos = 0; +} + +void fdc_fifo_buf_write(int val) +{ + if (fdc.fifobufpos < fdc.tfifo) + { + fdc.fifobuf[fdc.fifobufpos] = val; + fdc.fifobufpos++; + fdc.fifobufpos %= fdc.tfifo; + // pclog("FIFO buffer position = %02X\n", fdc.fifobufpos); + if (fdc.fifobufpos == fdc.tfifo) fdc.fifobufpos = 0; + } +} + +int fdc_fifo_buf_read() +{ + int temp = 0; + if (fdc.fifobufpos < fdc.tfifo) + { + temp = fdc.fifobuf[fdc.fifobufpos]; + fdc.fifobufpos++; + fdc.fifobufpos %= fdc.tfifo; + // pclog("FIFO buffer position = %02X\n", fdc.fifobufpos); + if (fdc.fifobufpos == fdc.tfifo) fdc.fifobufpos = 0; + } + return temp; +} + +/* For DMA mode, just goes ahead in FIFO buffer but doesn't actually read or write anything. */ +void fdc_fifo_buf_dummy() +{ + if (fdc.fifobufpos < fdc.tfifo) + { + fdc.fifobufpos++; + fdc.fifobufpos %= fdc.tfifo; + // pclog("FIFO buffer position = %02X\n", fdc.fifobufpos); + if (fdc.fifobufpos == fdc.tfifo) fdc.fifobufpos = 0; + } +} + +static void fdc_int() +{ + pclog("FDC interrupt issued\n"); + if (!fdc.pcjr) + picint(1 << 6); +} + +static void fdc_watchdog_poll(void *p) +{ + FDC *fdc = (FDC *)p; + + fdc->watchdog_count--; + if (fdc->watchdog_count) + fdc->watchdog_timer += 1000 * TIMER_USEC; + else + { +// pclog("Watchdog timed out\n"); + + fdc->watchdog_timer = 0; + if (fdc->dor & 0x20) + picint(1 << 6); + } +} + +/* fdc.rwc per Winbond W83877F datasheet: + 0 = normal; + 1 = 500 kbps, 360 rpm; + 2 = 500 kbps, 300 rpm; + 3 = 250 kbps + + Drive is only aware of selected rate and densel, so on real hardware, the rate expected by FDC and the rate actually being + processed by drive can mismatch, in which case the FDC won't receive the correct data. +*/ + +int bit_rate = 250; + +void fdc_update_is_nsc(int is_nsc) +{ + fdc.is_nsc = is_nsc; +} + +void fdc_update_enh_mode(int enh_mode) +{ + fdc.enh_mode = enh_mode; +} + +int fdc_get_rwc(int drive) +{ + return fdc.rwc[drive]; +} + +void fdc_update_rwc(int drive, int rwc) +{ + fdc.rwc[drive] = rwc; +} + +int fdc_get_boot_drive() +{ + return fdc.boot_drive; +} + +void fdc_update_boot_drive(int boot_drive) +{ + fdc.boot_drive = boot_drive; +} + +void fdc_update_densel_polarity(int densel_polarity) +{ + fdc.densel_polarity = densel_polarity; +} + +void fdc_update_densel_force(int densel_force) +{ + fdc.densel_force = densel_force; +} + +void fdc_update_drvrate(int drive, int drvrate) +{ + fdc.drvrate[drive] = drvrate; +} + +void fdc_update_drv2en(int drv2en) +{ + fdc.drv2en = drv2en; +} + +void fdc_update_rate(int drive) +{ + if ((fdc.rwc[drive] == 1) || (fdc.rwc[drive] == 2)) + { + bit_rate = 500; + } + else if (fdc.rwc[drive] == 3) + { + bit_rate = 250; + } + else switch (fdc.rate) + { + case 0: /*High density*/ + bit_rate = 500; + break; + case 1: /*Double density (360 rpm)*/ + switch(fdc.drvrate[drive]) + { + case 0: + bit_rate = 300; + break; + case 1: + bit_rate = 500; + break; + case 2: + bit_rate = 2000; + break; + } + break; + case 2: /*Double density*/ + bit_rate = 250; + break; + case 3: /*Extended density*/ + bit_rate = 1000; + break; + } + + fdc.bitcell_period = 1000000 / bit_rate*2; /*Bitcell period in ns*/ + pclog("fdc_update_rate: rate=%i bit_rate=%i bitcell_period=%i\n", fdc.rate, bit_rate, fdc.bitcell_period); +} + +int fdc_get_bitcell_period() +{ + return fdc.bitcell_period; +} + +static int fdc_get_densel(int drive) +{ + switch (fdc.rwc[drive]) + { + case 1: + case 3: + return 0; + case 2: + return 1; + } + + if (!fdc.is_nsc) + { + switch (fdc.densel_force) + { + case 2: + return 1; + case 3: + return 0; + } + } + else + { + switch (fdc.densel_force) + { + case 0: + return 0; + case 1: + return 1; + } + } + + switch (fdc.rate) + { + case 0: + case 3: + return fdc.densel_polarity ? 1 : 0; + case 1: + case 2: + return fdc.densel_polarity ? 0 : 1; + } +} + +static void fdc_rate(int drive) +{ + fdc_update_rate(drive); + disc_set_rate(drive, fdc.drvrate[drive], fdc.rate); + fdd_set_densel(fdc_get_densel(drive)); + // pclog("Drive %i: enh. %i, rate %i, DENSEL %i, RWC %i, drvrate %i, densel polarity %i, NSC %i, densel force %i\n", drive, fdc.enh_mode, fdc.rate, fdc_get_densel(drive), fdc_get_rwc(drive), fdc.drvrate[drive], fdc.densel_polarity, fdc.is_nsc, fdc.densel_force); +} + +void fdc_seek(int drive, int params) +{ + fdd_seek(drive, params); + fdc.stat |= (1 << fdc.drive); + // fdc_state = FDC_STATE_SEEK; + pclog("FDC seek issued\n"); +} + +void fdc_write(uint16_t addr, uint8_t val, void *priv) +{ +// pclog("Write FDC %04X %02X %04X:%04X %i %02X %i rate=%i %i\n",addr,val,cs>>4,pc,ins,fdc.st0,ins,fdc.rate, fdc.data_ready); + int drive; + + // pclog("fdc_write: %04X: %02X\n", addr, val); + switch (addr&7) + { + case 1: return; + case 2: /*DOR*/ +// if (val == 0xD && (cs >> 4) == 0xFC81600 && ins > 769619936) output = 3; +// printf("DOR was %02X\n",fdc.dor); + if (fdc.pcjr) + { + if ((fdc.dor & 0x40) && !(val & 0x40)) + { + fdc.watchdog_timer = 1000 * TIMER_USEC; + fdc.watchdog_count = 1000; + picintc(1 << 6); +// pclog("watchdog set %i %i\n", fdc.watchdog_timer, TIMER_USEC); + } + if ((val & 0x80) && !(fdc.dor & 0x80)) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + discint=-1; + fdc_reset(); + } + motor_on[0] = val & 0x01; + fdc.drive = 0; +/* if (motor_on[0]) + output = 3; + else + output = 0;*/ + } + else + { + if (val&4) + { + fdc.stat=0x80; + fdc.pnum=fdc.ptot=0; + } + if ((val&4) && !(fdc.dor&4)) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + discint=-1; + fdc_reset(); + } + timer_process(); + fdc.drive = val & 3; + val &= 0x3F; + /* if (fdc.drive > 2) + { + motor_on = 0; + } */ + if (fdc.drive == 1) + { + if ((!fdc.drv2en) || (fdd_get_type(1) == 0)) + { + motor_on[1] = 0; + val &= 0xDF; + } + else + { + motor_on[1] = val & 0x20; + } + } + else if (fdc.drive == 0) + { + if (fdd_get_type(0) == 0) + { + motor_on[0] = 0; + val &= 0xEF; + } + else + { + motor_on[0] = val & 0x10; + } + } + fdc_set_skip_pulses(fdc.drive, 0); + timer_update_outstanding(); + } + fdc.dor=val; +// printf("DOR now %02X\n",val); + return; + case 3: + /* TDR */ + if (fdc.enh_mode) + { + drive = (fdc.dor & 1) ^ fdd_swap; + fdc.rwc[drive] = (val & 0x30) >> 4; + } + return; + case 4: + if (val & 0x80) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + discint=-1; + fdc_reset(); + } + return; + case 5: /*Command register*/ + if ((fdc.stat & 0xf0) == 0xb0) + { + if (fdc.pcjr || !fdc.fifo) + { + fdc.dat = val; + fdc.stat &= ~0x80; + } + else + { + fdc_fifo_buf_write(val); + if (fdc.fifobufpos == 0) fdc.stat &= ~0x80; + } + break; + } +// if (fdc.inread) +// rpclog("c82c711_fdc_write : writing while inread! %02X\n", val); +// rpclog("Write command reg %i %i\n",fdc.pnum, fdc.ptot); + if (fdc.pnum==fdc.ptot) + { + fdc.tc = 0; + fdc.data_ready = 0; + + fdc.command=val; +// pclog("Starting FDC command %02X\n",fdc.command); + switch (fdc.command&0x1F) + { + case 1: /*Mode*/ + if (!fdc.is_nsc) goto bad_command; + fdc.pnum=0; + fdc.ptot=4; + fdc.stat=0x90; + fdc.pos=0; + fdc.format_state = 0; + break; + + case 2: /*Read track*/ + fdc.pnum=0; + fdc.ptot=8; + fdc.stat=0x90; + fdc.pos=0; + break; + case 3: /*Specify*/ + fdc.pnum=0; + fdc.ptot=2; + fdc.stat=0x90; + break; + case 4: /*Sense drive status*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + break; + case 5: /*Write data*/ +// printf("Write data!\n"); + fdc.pnum=0; + fdc.ptot=8; + fdc.stat=0x90; + fdc.pos=0; +// readflash=1; + break; + case 6: /*Read data*/ + fdc.pnum=0; + fdc.ptot=8; + fdc.stat=0x90; + fdc.pos=0; + break; + case 7: /*Recalibrate*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + break; + case 8: /*Sense interrupt status*/ +// printf("Sense interrupt status %i\n",curdrive); + fdc.lastdrive = fdc.drive; +// fdc.stat = 0x10 | (fdc.stat & 0xf); +// fdc_time=1024; + discint = 8; + fdc.pos = 0; + fdc_callback(); + break; + case 10: /*Read sector ID*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + fdc.pos=0; + break; + case 0x0d: /*Format track*/ + fdc.pnum=0; + fdc.ptot=5; + fdc.stat=0x90; + fdc.pos=0; + fdc.format_state = 0; + break; + case 15: /*Seek*/ + fdc.pnum=0; + fdc.ptot=2; + fdc.stat=0x90; + fdc.seek_params = val & 0xC0; + break; + case 0x0e: /*Dump registers*/ + fdc.lastdrive = fdc.drive; + discint = 0x0e; + fdc.pos = 0; + fdc_callback(); + break; + case 0x10: /*Get version*/ + fdc.lastdrive = fdc.drive; + discint = 0x10; + fdc.pos = 0; + fdc_callback(); + break; + case 0x12: /*Set perpendicular mode*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + fdc.pos=0; + break; + case 0x13: /*Configure*/ + fdc.pnum=0; + fdc.ptot=3; + fdc.stat=0x90; + fdc.pos=0; + break; + case 0x14: /*Unlock*/ + case 0x94: /*Lock*/ + fdc.lastdrive = fdc.drive; + discint = fdc.command; + fdc.pos = 0; + fdc_callback(); + break; + + case 0x18: + if (!fdc.is_nsc) goto bad_command; + fdc.lastdrive = fdc.drive; + discint = 0x10; + fdc.pos = 0; + fdc_callback(); + /* fdc.stat = 0x10; + discint = 0xfc; + fdc_callback(); */ + break; + + default: +bad_command: + // fatal("Bad FDC command %02X\n",val); +// dumpregs(); +// exit(-1); + fdc.stat=0x10; + discint=0xfc; + timer_process(); + disctime = 200 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + break; + } + } + else + { + fdc.params[fdc.pnum++]=val; + if (fdc.pnum==fdc.ptot) + { +// pclog("Got all params %02X\n", fdc.command); + fdc.stat=0x30; + discint=fdc.command&0x1F; + timer_process(); + disctime = 1024 * (1 << TIMER_SHIFT); + timer_update_outstanding(); +// fdc.drive = fdc.params[0] & 3; + disc_drivesel = fdc.drive & 1; + fdc_reset_stat = 0; + disc_set_drivesel(fdc.drive & 1); + switch (discint) + { + case 2: /*Read a track*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + fdc.head=fdc.params[2]; + fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); + fdc.sector=fdc.params[3]; + fdc.eot[fdc.drive] = fdc.params[5]; + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + if (fdc.config & 0x40) + { + if (fdc.params[1] != fdc.track[fdc.drive]) + { + fdc_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + fdc.track[fdc.drive] = fdc.params[1]; + } + } + // fdc.track[fdc.drive]=fdc.params[1]; + fdc.rw_track = fdc.params[1]; +// pclog("Read a track track=%i head=%i sector=%i eot=%i\n", fdc.track[fdc.drive], fdc.head, fdc.sector, fdc.eot[fdc.drive]); + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + + if (fdc_state != FDC_STATE_SEEK) + disc_readsector(fdc.drive, SECTOR_FIRST, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + + disctime = (fdc_state == FDC_STATE_SEEK) ? (790 * TIMER_USEC) : 0; + readflash = 1; + fdc.inread = 1; + break; + + case 3: /*Specify*/ + fdc.stat=0x80; + fdc.specify[0] = fdc.params[0]; + fdc.specify[1] = fdc.params[1]; + fdc.dma = (fdc.specify[1] & 1) ^ 1; + disctime = 0; + break; + + case 5: /*Write data*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + fdc.head=fdc.params[2]; + fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); + fdc.sector=fdc.params[3]; + fdc.eot[fdc.drive] = fdc.params[5]; + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + if (fdc.config & 0x40) + { + if (fdc.params[1] != fdc.track[fdc.drive]) + { + fdc_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + fdc.track[fdc.drive] = fdc.params[1]; + } + } + // fdc.track[fdc.drive]=fdc.params[1]; + fdc.rw_track = fdc.params[1]; + + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + + if (fdc_state != FDC_STATE_SEEK) + disc_writesector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + + disctime = (fdc_state == FDC_STATE_SEEK) ? (790 * TIMER_USEC) : 0; + fdc.written = 0; + readflash = 1; + fdc.pos = 0; + if (fdc_state != FDC_STATE_SEEK) + { + if (fdc.pcjr) + fdc.stat = 0xb0; + } + break; + + case 6: /*Read data*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + fdc.head=fdc.params[2]; + fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); + fdc.sector=fdc.params[3]; + fdc.eot[fdc.drive] = fdc.params[5]; + // pclog("FDC track is %i, requested track is %i\n", fdc.track[fdc.drive], fdc.params[1]); + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + + if (fdc.config & 0x40) + { + if (fdc.params[1] != fdc.track[fdc.drive]) + { + fdc_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + fdc.track[fdc.drive] = fdc.params[1]; + } + } + // fdc.track[fdc.drive]=fdc.params[1]; + fdc.rw_track = fdc.params[1]; + + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + + if (fdc_state != FDC_STATE_SEEK) + disc_readsector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + + disctime = (fdc_state == FDC_STATE_SEEK) ? (790 * TIMER_USEC) : 0; + readflash = 1; + fdc.inread = 1; + break; + + case 7: /*Recalibrate*/ + fdc.stat = 1 << fdc.drive; + disctime = 0; + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + else + { + // fdc_seek(fdc.drive, SEEK_RECALIBRATE); + fdc_seek(fdc.drive, -79); + } + disctime = 790 * TIMER_USEC; + break; + + case 0x0d: /*Format*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + fdc.head = (fdc.params[0] & 4) ? 1 : 0; + fdc.format_state = 1; + fdc.pos = 0; + fdc.stat = 0x30; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + break; + + case 0xf: /*Seek*/ + fdc.stat = 1 << fdc.drive; + fdc.head = (fdc.params[0] & 4) ? 1 : 0; + disctime = 0; + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + else + { + // pclog("Seeking (params=%02X, params[1]=%i)...\n", fdc.seek_params, fdc.params[1]); + if (fdc.seek_params & 0x80) + { + if (fdc.seek_params & 0x40) + { + /* Relative seek inwards. */ + fdc_seek(fdc.drive, fdc.params[1]); + } + else + { + /* Relative seek outwards. */ + fdc_seek(fdc.drive, -fdc.params[1]); + } + } + else + { + fdc_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + } + } + disctime = 790 * TIMER_USEC; +// pclog("Seek to %i\n", fdc.params[1]); + break; + + case 10: /*Read sector ID*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + disctime = 0; + fdc.head = (fdc.params[0] & 4) ? 1 : 0; + fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); +// pclog("Read sector ID %i %i\n", fdc.rate, fdc.drive); + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + if (((fdc.drive ^ fdd_swap) != 1) || fdc.drv2en) + disc_readaddress(fdc.drive, fdc.track[fdc.drive], fdc.head, fdc.rate); + else + fdc_notfound(); + break; + } + } + } + return; + case 7: + // if (!AT) return; + fdc.rate=val&3; + // pclog("Rate is now: %i\n", fdc.rate); + + disc_3f7=val; + return; + } +// printf("Write FDC %04X %02X\n",addr,val); +// dumpregs(); +// exit(-1); +} + +int paramstogo=0; +uint8_t fdc_read(uint16_t addr, void *priv) +{ + uint8_t temp; + int drive; +// /*if (addr!=0x3f4) */printf("Read FDC %04X %04X:%04X %04X %i %02X %02x %i ",addr,cs>>4,pc,BX,fdc.pos,fdc.st0,fdc.stat,ins); + switch (addr&7) + { + case 1: /*???*/ + drive = (fdc.dor & 1) ^ fdd_swap; + if (!fdc.enable_3f1) + return 0xff; +// temp=0x50; + temp = 0x70; + if (drive) + temp &= ~0x40; + else + temp &= ~0x20; + break; + case 3: + drive = (fdc.dor & 1) ^ fdd_swap; + if (fdc.ps1) + { + /*PS/1 Model 2121 seems return drive type in port 0x3f3, + despite the 82077AA FDC not implementing this. This is + presumably implemented outside the FDC on one of the + motherboard's support chips.*/ + /* NOTE by OBattler: This has to be implemented for + super I/O chips too. */ + if (fdd_is_525(drive)) + temp = 0x20; + else if (fdd_is_ed(drive)) + temp = 0x10; + else + temp = 0x00; + } + else if (!fdc.enh_mode) + temp = 0x20; + else + { + temp = fdc.rwc[drive] << 4; + } + break; + case 4: /*Status*/ + temp=fdc.stat; + break; + case 5: /*Data*/ + if ((fdc.stat & 0xf0) == 0xf0) + { + fdc.stat&=~0x80; + if (fdc.pcjr || !fdc.fifo) + temp = fdc.dat; + else + { + temp = fdc_fifo_buf_read(); + } + break; + } + fdc.stat&=~0x80; + if (paramstogo) + { + paramstogo--; + temp=fdc.res[10 - paramstogo]; +// pclog("Read param %i %02X\n",10-paramstogo,temp); + if (!paramstogo) + { + fdc.stat=0x80; +// fdc.st0=0; + } + else + { + fdc.stat|=0xC0; +// fdc_poll(); + } + } + else + { + if (lastbyte) + fdc.stat = 0x80; + lastbyte=0; + temp=fdc.dat; + fdc.data_ready = 0; + } + if (discint==0xA) + { + timer_process(); + disctime = 1024 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + } + fdc.stat &= 0xf0; + break; + case 7: /*Disk change*/ + drive = (fdc.dor & 1) ^ fdd_swap; + if (fdc.dor & (0x10 << drive)) + temp = (disc_changed[drive] || drive_empty[drive])?0x80:0; + else + temp = 0; + if (fdc.dskchg_activelow) /*PC2086/3086 seem to reverse this bit*/ + temp ^= 0x80; +// printf("- DC %i %02X %02X %i %i - ",fdc.dor & 1, fdc.dor, 0x10 << (fdc.dor & 1), discchanged[fdc.dor & 1], driveempty[fdc.dor & 1]); +// discchanged[fdc.dor&1]=0; + break; + default: + temp=0xFF; +// printf("Bad read FDC %04X\n",addr); +// dumpregs(); +// exit(-1); + } +// /*if (addr!=0x3f4) */printf("%02X rate=%i %i\n",temp,fdc.rate, fdc.data_ready); + // pclog("fdc_read: %04X: %02X\n", addr, temp); + return temp; +} + +void fdc_callback() +{ + int temp; + disctime = 0; +// pclog("fdc_callback %i %i\n", discint, disctime); +// if (fdc.inread) +// rpclog("c82c711_fdc_callback : while inread! %08X %i %02X %i\n", discint, fdc.drive, fdc.st0, ins); + if (fdc_state == FDC_STATE_SEEK) + { + if (!fdd_stepping_motor_on[fdc.drive ^ fdd_swap]) + { + pclog("FDC has stopped seeking\n"); + fdc_state = FDC_STATE_NORMAL; + + fdc.stat &= ~(1 << fdc.drive); + + switch (discint) + { + case 2: + disc_readsector(fdc.drive, SECTOR_FIRST, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + disctime = 0; + readflash = 1; + fdc.inread = 1; + return; + case 5: + disc_writesector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + disctime = 0; + fdc.written = 0; + readflash = 1; + fdc.pos = 0; + if (fdc.pcjr) + fdc.stat = 0xb0; + return; + case 6: + disc_readsector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + disctime = 0; + readflash = 1; + fdc.inread = 1; + return; + case 7: + case 0xf: + break; + default: + return; + } + } + else + { + pclog("FDC is seeking\n"); + return; + } + } + else + { + if (fdd_stepping_motor_on[fdc.drive ^ fdd_swap]) + pclog("FDD is seeking but FDC not\n"); + else + pclog("Neither the FDD nor the FDC is seeking\n"); + } + + switch (discint) + { + case -3: /*End of command with interrupt*/ +// if (output) printf("EOC - interrupt!\n"); +//rpclog("EOC\n"); + fdc_int(); + case -2: /*End of command*/ + fdc.stat = (fdc.stat & 0xf) | 0x80; + return; + case -1: /*Reset*/ +//rpclog("Reset\n"); + fdc_int(); + fdc_reset_stat = 4; + return; + case 1: /*Mode*/ + fdc.stat=0x80; + fdc.densel_force = (fdc.params[2] & 0xC0) >> 6; + return; + + case 2: /*Read track*/ + readflash = 1; + fdc.eot[fdc.drive]--; +// pclog("Read a track callback, eot=%i\n", fdc.eot[fdc.drive]); + if (!fdc.eot[fdc.drive] || fdc.tc) + { +// pclog("Complete\n"); + fdc.inread = 0; + discint=-2; + fdc_int(); + fdc_set_skip_pulses(fdc.drive, 0); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=fdc.res[6]=0; + fdc.res[7]=fdc.rw_track; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + return; + } + else + { + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + not_found[fdc.drive ^ fdd_swap] = 1000; +#if 0 + disc_notfound = 1000; +#endif + else + disc_readsector(fdc.drive, SECTOR_NEXT, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]); + } + fdc.inread = 1; + return; + case 4: /*Sense drive status*/ + fdc.res[10] = (fdc.params[0] & 7) | 0x28; + if (((fdc.drive ^ fdd_swap) != 1) || fdc.drv2en) + { + if (fdd_track0(fdc.drive ^ fdd_swap)) + fdc.res[10] |= 0x10; + } + if (writeprot[fdc.drive]) + fdc.res[10] |= 0x40; + + fdc.stat = (fdc.stat & 0xf) | 0xd0; + paramstogo = 1; + discint = 0; + disctime = 0; + return; + case 5: /*Write data*/ + readflash = 1; + fdc.sector++; + if (fdc.sector > fdc.params[5]) + { + fdc.sector = 1; + if (fdc.command & 0x80) + { + fdc.head ^= 1; + if (!fdc.head) + { + fdc.rw_track++; +// fdc.track[fdc.drive]++; +/* if (fdc.track[fdc.drive] >= 79) + { + fdc.track[fdc.drive] = 79; + fdc.tc = 1; + }*/ + } + } + else + { + fdc.rw_track++; +// fdc.track[fdc.drive]++; + fdc.tc = 1; + } + } + if (fdc.tc) + { + discint=-2; + fdc_int(); + fdc_set_skip_pulses(fdc.drive, 0); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=fdc.res[6]=0; + fdc.res[7]=fdc.rw_track; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + return; + } + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + not_found[fdc.drive ^ fdd_swap] = 1000; +#if 0 + disc_notfound = 1000; +#endif + else + disc_writesector(fdc.drive, fdc.sector, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]); +// ioc_fiq(IOC_FIQ_DISC_DATA); + return; + case 6: /*Read data*/ +// rpclog("Read data %i\n", fdc.tc); + readflash = 1; + fdc_set_skip_pulses(fdc.drive, 1); + fdc.sector++; + if (fdc.sector > fdc.params[5]) + { + fdc.sector = 1; + if (fdc.command & 0x80) + { + fdc.head ^= 1; + if (!fdc.head) + { + fdc.rw_track++; +// fdc.track[fdc.drive]++; +/* if (fdc.track[fdc.drive] >= 79) + { + fdc.track[fdc.drive] = 79; + fdc.tc = 1; + }*/ + } + } + else + { + fdc.rw_track++; +// fdc.track[fdc.drive]++; + fdc.tc = 1; + } + } + if (fdc.tc) + { + fdc.inread = 0; + discint=-2; + fdc_int(); + fdc_set_skip_pulses(fdc.drive, 0); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=fdc.res[6]=0; + fdc.res[7]=fdc.rw_track; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + return; + } + fdc_set_skip_pulses(fdc.drive, 0); + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + not_found[fdc.drive ^ fdd_swap] = 1000; +#if 0 + disc_notfound = 1000; +#endif + else + disc_readsector(fdc.drive, fdc.sector, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]); + fdc.inread = 1; + return; + + case 7: /*Recalibrate*/ + fdc.track[fdc.drive]=0; +// if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0; + if (fdc.drive <= 1) + fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0); + else + fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdc.head?4:0); + discint=-3; + timer_process(); + disctime = 2048 * (1 << TIMER_SHIFT); + timer_update_outstanding(); +// printf("Recalibrate complete!\n"); + fdc.stat = 0x80 | (1 << fdc.drive); + return; + + case 8: /*Sense interrupt status*/ +// pclog("Sense interrupt status %i\n", fdc_reset_stat); + + fdc.stat = (fdc.stat & 0xf) | 0xd0; + if (fdc_reset_stat) + fdc.res[9] = 0xc0 | (4 - fdc_reset_stat) | (fdc.head ? 4 : 0); + else + fdc.res[9] = fdc.st0; + fdc.res[10] = fdc.track[fdc.drive]; + if (!fdc_reset_stat) + fdc.st0 = 0x80; + else + fdc_reset_stat--; + + paramstogo = 2; + discint = 0; + disctime = 0; + return; + + case 0x0d: /*Format track*/ +// rpclog("Format\n"); + if (fdc.format_state == 1) + { +// ioc_fiq(IOC_FIQ_DISC_DATA); + fdc.format_state = 2; + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + } + else if (fdc.format_state == 2) + { + temp = fdc_getdata(fdc.pos == ((fdc.params[2] * 4) - 1)); + if (temp == -1) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + return; + } + fdc.format_dat[fdc.pos++] = temp; + if (fdc.pos == (fdc.params[2] * 4)) + fdc.format_state = 3; + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + } + else if (fdc.format_state == 3) + { +// pclog("Format next stage track %i head %i\n", fdc.track[fdc.drive], fdc.head); + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + not_found[fdc.drive ^ fdd_swap] = 1000; +#if 0 + disc_notfound = 1000; +#endif + else + disc_format(fdc.drive, disc_realtrack(fdc.drive, fdc.track[fdc.drive]), fdc.head, fdc.rate, fdc.params[4]); + fdc.format_state = 4; + } + else + { + discint=-2; + fdc_int(); + fdc_set_skip_pulses(fdc.drive, 0); + fdc.stat=0xD0; + fdc.res[4] = (fdc.head?4:0)|fdc.drive; + fdc.res[5] = fdc.res[6] = 0; + fdc.res[7] = fdc.track[fdc.drive]; + fdc.res[8] = fdc.head; + fdc.res[9] = fdc.format_dat[fdc.pos - 2] + 1; + fdc.res[10] = fdc.params[4]; + paramstogo=7; + fdc.format_state = 0; + return; + } + return; + + case 15: /*Seek*/ + fdc.track[fdc.drive]=fdc.params[1]; +// if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0; +// printf("Seeked to track %i %i\n",fdc.track[fdc.drive], fdc.drive); + if (fdc.drive <= 1) + fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0); + else + fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdc.head?4:0); + discint=-3; + timer_process(); + disctime = 2048 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + fdc.stat = 0x80 | (1 << fdc.drive); +// pclog("Stat %02X ST0 %02X\n", fdc.stat, fdc.st0); + return; + case 0x0e: /*Dump registers*/ + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[3] = fdc.track[0]; + fdc.res[4] = fdc.track[1]; + fdc.res[5] = 0; + fdc.res[6] = 0; + fdc.res[7] = fdc.specify[0]; + fdc.res[8] = fdc.specify[1]; + fdc.res[9] = fdc.eot[fdc.drive]; + fdc.res[10] = (fdc.perp & 0x7f) | ((fdc.lock) ? 0x80 : 0); + paramstogo=10; + discint=0; + disctime = 0; + return; + + case 0x10: /*Version*/ + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0x90; + paramstogo=1; + discint=0; + disctime = 0; + return; + + case 0x12: + fdc.perp = fdc.params[0]; + fdc.stat = 0x80; + disctime = 0; +// picint(0x40); + return; + case 0x13: /*Configure*/ + fdc.config = fdc.params[1]; + fdc.pretrk = fdc.params[2]; + fdc.fifo = (fdc.params[1] & 0x20) ? 0 : 1; + fdc.tfifo = (fdc.params[1] & 0xF) + 1; + // pclog("FIFO is now %02X, threshold is %02X\n", fdc.fifo, fdc.tfifo); + fdc.stat = 0x80; + disctime = 0; +// picint(0x40); + return; + case 0x14: /*Unlock*/ + fdc.lock = 0; + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0; + paramstogo=1; + discint=0; + disctime = 0; + return; + case 0x94: /*Lock*/ + fdc.lock = 1; + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0x10; + paramstogo=1; + discint=0; + disctime = 0; + return; + + case 0x18: /*NSC*/ + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0x73; + paramstogo=1; + discint=0; + disctime = 0; + return; + + case 0xfc: /*Invalid*/ + fdc.dat = fdc.st0 = 0x80; +// pclog("Inv!\n"); + //picint(0x40); + fdc.stat = (fdc.stat & 0xf) | 0xd0; +// fdc.stat|=0xC0; + fdc.res[10] = fdc.st0; + paramstogo=1; + discint=0; + disctime = 0; + return; + } +// printf("Bad FDC disc int %i\n",discint); +// dumpregs(); +// exit(-1); +} + +void fdc_overrun() +{ + disc_sector_stop(fdc.drive ^ fdd_swap); + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0x10; /*Overrun*/ + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +} + +int fdc_data(uint8_t data) +{ + if (fdc.tc) + return 0; + + if (fdc.pcjr || !fdc.dma) + { + if (fdc.data_ready) + { + fdc_overrun(); +// pclog("Overrun\n"); + return -1; + } + + if (fdc.pcjr || !fdc.fifo) + { + fdc.dat = data; + fdc.data_ready = 1; + fdc.stat = 0xf0; + } + else + { + // FIFO enabled + fdc_fifo_buf_write(data); + if (fdc.fifobufpos == 0) + { + // We have wrapped around, means FIFO is over + fdc.data_ready = 1; + fdc.stat = 0xf0; + } + } + } + else + { + if (dma_channel_write(2, data) & DMA_OVER) + fdc.tc = 1; + + if (!fdc.fifo) + { + fdc.data_ready = 1; + fdc.stat = 0xd0; + } + else + { + fdc_fifo_buf_dummy(); + if (fdc.fifobufpos == 0) + { + // We have wrapped around, means FIFO is over + fdc.data_ready = 1; + fdc.stat = 0xd0; + } + } + } + + return 0; +} + +void fdc_finishread(int drive) +{ + pclog("Read finished\n"); + fdc_set_skip_pulses(drive, 1); + disctime = 200 * TIMER_USEC; +// rpclog("fdc_finishread\n"); +} + +void fdc_notfound() +{ + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=5; + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +// rpclog("c82c711_fdc_notfound\n"); +} + +void fdc_datacrcerror() +{ + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0x20; /*Data error*/ + fdc.res[6]=0x20; /*Data error in data field*/ + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +// rpclog("c82c711_fdc_datacrcerror\n"); +} + +void fdc_headercrcerror() +{ + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0x20; /*Data error*/ + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +// rpclog("c82c711_fdc_headercrcerror\n"); +} + +void fdc_writeprotect() +{ + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0x02; /*Not writeable*/ + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +} + +int fdc_getdata(int last) +{ + int data; + + if (fdc.pcjr || !fdc.dma) + { + if (fdc.written) + { + fdc_overrun(); +// pclog("Overrun\n"); + return -1; + } + if (fdc.pcjr || !fdc.fifo) + { + data = fdc.dat; + + if (!last) + fdc.stat = 0xb0; + } + else + { + data = fdc_fifo_buf_read(); + + if (!last && (fdc.fifobufpos == 0)) + fdc.stat = 0xb0; + } + } + else + { + data = dma_channel_read(2); + + if (!fdc.fifo) + { + if (!last) + fdc.stat = 0x90; + } + else + { + fdc_fifo_buf_dummy(); + + if (!last && (fdc.fifobufpos == 0)) + fdc.stat = 0x90; + } + + if (data & DMA_OVER) + fdc.tc = 1; + } + + fdc.written = 0; + return data & 0xff; +} + +void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2) +{ +// pclog("SectorID %i %i %i %i\n", track, side, sector, size); + fdc_int(); + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0; + fdc.res[6]=0; + fdc.res[7]=track; + fdc.res[8]=side; + fdc.res[9]=sector; + fdc.res[10]=size; + paramstogo=7; +} + +void fdc_indexpulse() +{ +// ioc_irqa(IOC_IRQA_DISC_INDEX); +// rpclog("c82c711_fdc_indexpulse\n"); +} + +void fdc_init() +{ + timer_add(fdc_callback, &disctime, &disctime, NULL); + fdc.dskchg_activelow = 0; + fdc.enable_3f1 = 1; + + fdc_update_enh_mode(0); + fdc_update_densel_polarity(1); + fdc_update_rwc(0, 0); + fdc_update_rwc(1, 0); + fdc_update_densel_force(0); + fdc_update_drv2en(1); + + fdc_set_skip_pulses(0, 0); + fdc_set_skip_pulses(1, 0); + + fdd_init(); + + swwp = 0; + disable_write = 0; + + fdd_stepping_motor_on[0] = fdd_track_diff[0] = 0; + fdd_stepping_motor_on[1] = fdd_track_diff[1] = 0; + fdc_state = FDC_STATE_NORMAL; + + fdc.fifo = fdc.tfifo = 0; +} + +void fdc_add() +{ + io_sethandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + fdc.pcjr = 0; + fdc.ps1 = 0; +} + +void fdc_add_for_superio() +{ + io_sethandler(0x03f2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + fdc.pcjr = 0; + fdc.ps1 = 0; +} + +void fdc_add_pcjr() +{ + io_sethandler(0x00f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + timer_add(fdc_watchdog_poll, &fdc.watchdog_timer, &fdc.watchdog_timer, &fdc); + fdc.pcjr = 1; + fdc.ps1 = 0; +} + +void fdc_remove() +{ + io_removehandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + io_removehandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); +} + +void fdc_set_ps1() +{ + fdc.ps1 = 1; +} + +void fdc_discchange_clear(int drive) +{ + if (drive < 2) + disc_changed[drive] = 0; +} + +void fdc_set_dskchg_activelow() +{ + fdc.dskchg_activelow = 1; +} + +void fdc_3f1_enable(int enable) +{ + fdc.enable_3f1 = enable; +} diff --git a/src/fdc.h b/src/fdc.h new file mode 100644 index 000000000..7650988c5 --- /dev/null +++ b/src/fdc.h @@ -0,0 +1,27 @@ +void fdc_init(); +void fdc_add(); +void fdc_add_for_superio(); +void fdc_add_pcjr(); +void fdc_add_tandy(); +void fdc_remove(); +void fdc_reset(); +void fdc_poll(); +void fdc_abort(); +void fdc_discchange_clear(int drive); +void fdc_set_dskchg_activelow(); +void fdc_3f1_enable(int enable); +void fdc_set_ps1(); +int fdc_get_bitcell_period(); + +/* A few functions to communicate between Super I/O chips and the FDC. */ +void fdc_update_is_nsc(int is_nsc); +void fdc_update_enh_mode(int enh_mode); +int fdc_get_rwc(int drive); +void fdc_update_rwc(int drive, int rwc); +int fdc_get_boot_drive(); +void fdc_update_boot_drive(int boot_drive); +void fdc_update_densel_polarity(int densel_polarity); +void fdc_update_densel_force(int densel_force); +void fdc_update_drvrate(int drive, int drvrate); +void fdc_update_drv2en(int drv2en); +int fdc_skip_pulses(int drive); diff --git a/src/fdc37c665.c b/src/fdc37c665.c new file mode 100644 index 000000000..8a3f80904 --- /dev/null +++ b/src/fdc37c665.c @@ -0,0 +1,165 @@ +#include "ibm.h" + +#include "fdc.h" +#include "fdd.h" +#include "io.h" +#include "lpt.h" +#include "serial.h" +#include "fdc37c665.h" + +static uint8_t fdc37c665_lock[2]; +static int fdc37c665_curreg; +static uint8_t fdc37c665_regs[16]; + +static void write_lock(uint8_t val) +{ + if (val == 0x55 && fdc37c665_lock[1] == 0x55) + fdc_3f1_enable(0); + if (fdc37c665_lock[0] == 0x55 && fdc37c665_lock[1] == 0x55 && val != 0x55) + fdc_3f1_enable(1); + + fdc37c665_lock[0] = fdc37c665_lock[1]; + fdc37c665_lock[1] = val; +} + +void fdc37c665_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("Write SuperIO %04x %02x\n", port, val); + if (fdc37c665_lock[0] == 0x55 && fdc37c665_lock[1] == 0x55) + { + if (port == 0x3f0) + { + if (val == 0xaa) + write_lock(val); + else + fdc37c665_curreg = val & 0xf; + } + else + { + uint16_t com3_addr, com4_addr; + fdc37c665_regs[fdc37c665_curreg] = val; +// pclog("Write superIO %02x %02x %04x(%08x):%08x\n", fdc37c665_curreg, val, CS, cs, pc); + + switch (fdc37c665_regs[1] & 0x60) + { + case 0x00: + com3_addr = 0x338; + com4_addr = 0x238; + break; + case 0x20: + com3_addr = 0x3e8; + com4_addr = 0x2e8; + break; + case 0x40: + com3_addr = 0x3e8; + com4_addr = 0x2e0; + break; + case 0x60: + com3_addr = 0x220; + com4_addr = 0x228; + break; + } + + if (!(fdc37c665_regs[2] & 4)) + serial1_remove(); + else switch (fdc37c665_regs[2] & 3) + { + case 0: + serial1_set(0x3f8, 4); + break; + case 1: + serial1_set(0x2f8, 4); + break; + case 2: + serial1_set(com3_addr, 4); + break; + case 3: + serial1_set(com4_addr, 4); + break; + } + + if (!(fdc37c665_regs[2] & 0x40)) + serial2_remove(); + else switch (fdc37c665_regs[2] & 0x30) + { + case 0x00: + serial2_set(0x3f8, 3); + break; + case 0x10: + serial2_set(0x2f8, 3); + break; + case 0x20: + serial2_set(com3_addr, 3); + break; + case 0x30: + serial2_set(com4_addr, 3); + break; + } + + lpt1_remove(); + lpt2_remove(); + switch (fdc37c665_regs[1] & 3) + { + case 1: + lpt1_init(0x3bc); + break; + case 2: + lpt1_init(0x378); + break; + case 3: + lpt1_init(0x278); + break; + } + + fdc_update_enh_mode((fdc37c665_regs[3] & 2) ? 1 : 0); + + fdc_update_densel_force((fdc37c665_regs[5] & 0x18) >> 3); + fdd_swap = ((fdc37c665_regs[5] & 0x20) >> 5); + } + } + else + { + if (port == 0x3f0) + write_lock(val); + } +} + +uint8_t fdc37c665_read(uint16_t port, void *priv) +{ +// pclog("Read SuperIO %04x %02x\n", port, fdc37c665_curreg); + if (fdc37c665_lock[0] == 0x55 && fdc37c665_lock[1] == 0x55) + { + if (port == 0x3f1) + return fdc37c665_regs[fdc37c665_curreg]; + } + return 0xff; +} + +void fdc37c665_init() +{ + io_sethandler(0x03f0, 0x0002, fdc37c665_read, NULL, NULL, fdc37c665_write, NULL, NULL, NULL); + + fdc_update_is_nsc(0); + + fdc37c665_lock[0] = fdc37c665_lock[1] = 0; + fdc37c665_regs[0x0] = 0x3b; + fdc37c665_regs[0x1] = 0x9f; + fdc37c665_regs[0x2] = 0xdc; + fdc37c665_regs[0x3] = 0x78; + fdc37c665_regs[0x4] = 0x00; + fdc37c665_regs[0x5] = 0x00; + fdc37c665_regs[0x6] = 0xff; + fdc37c665_regs[0x7] = 0x00; + fdc37c665_regs[0x8] = 0x00; + fdc37c665_regs[0x9] = 0x00; + fdc37c665_regs[0xa] = 0x00; + fdc37c665_regs[0xb] = 0x00; + fdc37c665_regs[0xc] = 0x00; + fdc37c665_regs[0xd] = 0x65; + fdc37c665_regs[0xe] = 0x01; + fdc37c665_regs[0xf] = 0x00; + + fdc_update_densel_polarity(1); + fdc_update_densel_force(0); + fdd_swap = 0; +} diff --git a/src/fdc37c665.h b/src/fdc37c665.h new file mode 100644 index 000000000..1576c01c1 --- /dev/null +++ b/src/fdc37c665.h @@ -0,0 +1 @@ +extern void fdc37c665_init(); diff --git a/src/fdc37c932fr.c b/src/fdc37c932fr.c new file mode 100644 index 000000000..08b45ab91 --- /dev/null +++ b/src/fdc37c932fr.c @@ -0,0 +1,478 @@ +/* + SMSC SMC fdc37c932fr Super I/O Chip + Used by all some Acer boards, and by the Epox P55-VA +*/ + +#include "ibm.h" + +#include "fdc.h" +#include "fdd.h" +#include "ide.h" +#include "io.h" +#include "lpt.h" +#include "mouse_serial.h" +#include "serial.h" +#include "fdc37c932fr.h" + +static int fdc37c932fr_locked; +static int fdc37c932fr_curreg = 0; +static int fdc37c932fr_gpio_curreg = 0; +static uint8_t fdc37c932fr_regs[48]; +static uint8_t fdc37c932fr_ld_regs[10][256]; +static uint8_t fdc37c932fr_gpio_regs[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +static uint8_t tries; + +static uint16_t ld0_valid_ports[2] = {0x3F0, 0x370}; +static uint16_t ld1_valid_ports[2] = {0x1F0, 0x170}; +static uint16_t ld1_valid_ports2[2] = {0x3F6, 0x376}; +static uint16_t ld2_valid_ports[2] = {0x170, 0x1F0}; +static uint16_t ld2_valid_ports2[2] = {0x376, 0x3F6}; +static uint16_t ld3_valid_ports[3] = {0x3BC, 0x378, 0x278}; +static uint16_t ld4_valid_ports[9] = {0x3F8, 0x2F8, 0x338, 0x3E8, 0x2E8, 0x220, 0x238, 0x2E0, 0x228}; +static uint16_t ld5_valid_ports[9] = {0x3F8, 0x2F8, 0x338, 0x3E8, 0x2E8, 0x220, 0x238, 0x2E0, 0x228}; +static uint16_t ld5_valid_ports2[9] = {0x3F8, 0x2F8, 0x338, 0x3E8, 0x2E8, 0x220, 0x238, 0x2E0, 0x228}; + +static uint8_t is_in_array(uint16_t *port_array, uint8_t max, uint16_t port) +{ + uint8_t i = 0; + + for (i = 0; i < max; i++) + { + if (port_array[i] == port) return 1; + } + return 0; +} + +static uint16_t make_port(uint8_t ld) +{ + uint16_t r0 = fdc37c932fr_ld_regs[ld][0x60]; + uint16_t r1 = fdc37c932fr_ld_regs[ld][0x61]; + + uint16_t p = (r0 << 8) + r1; + + switch(ld) + { + case 0: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x3F0; + if (!(is_in_array(ld0_valid_ports, 2, p))) p = 0x3F0; + break; + case 1: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x1F0; + if (!(is_in_array(ld1_valid_ports, 2, p))) p = 0x1F0; + break; + case 2: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x170; + if (!(is_in_array(ld2_valid_ports, 2, p))) p = 0x170; + break; + case 3: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x378; + if (!(is_in_array(ld3_valid_ports, 3, p))) p = 0x378; + break; + case 4: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x3F8; + if (!(is_in_array(ld4_valid_ports, 9, p))) p = 0x3F8; + break; + case 5: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x2F8; + if (!(is_in_array(ld5_valid_ports, 9, p))) p = 0x2F8; + break; + } + + fdc37c932fr_ld_regs[ld][0x60] = (p >> 8); + fdc37c932fr_ld_regs[ld][0x61] = (p & 0xFF); + + return p; +} + +uint16_t make_port2(uint8_t ld) +{ + uint16_t r0 = fdc37c932fr_ld_regs[ld][0x62]; + uint16_t r1 = fdc37c932fr_ld_regs[ld][0x63]; + + uint16_t p = (r0 << 8) + r1; + + switch(ld) + { + case 1: + p &= 0xFFF; + if ((p < 0x100) || (p > 0xFF8)) p = 0x3F6; + if (!(is_in_array(ld1_valid_ports2, 2, p))) p = 0x3F6; + break; + case 2: + p &= 0xFFF; + if ((p < 0x100) || (p > 0xFF8)) p = 0x376; + if (!(is_in_array(ld2_valid_ports2, 2, p))) p = 0x376; + break; + case 5: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x3E8; + if (!(is_in_array(ld5_valid_ports2, 9, p))) p = 0x3E8; + break; + } + + fdc37c932fr_ld_regs[ld][0x62] = (p >> 8); + fdc37c932fr_ld_regs[ld][0x63] = (p & 0xFF); + + return p; +} + +void fdc37c932fr_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + if (port & 1) + { + if (fdc37c932fr_gpio_curreg && (fdc37c932fr_gpio_curreg <= 0xF)) + fdc37c932fr_gpio_regs[fdc37c932fr_gpio_curreg] = val; + } + else + { + fdc37c932fr_gpio_curreg = val; + } +} + +void fdc37c932fr_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint16_t ld_port = 0; + uint16_t ld_port2 = 0; + int temp; + // pclog("fdc37c932fr_write : port=%04x reg %02X = %02X locked=%i\n", port, fdc37c932fr_curreg, val, fdc37c932fr_locked); + + if (index) + { + if ((val == 0x55) && !fdc37c932fr_locked) + { + if (tries) + { + fdc37c932fr_locked = 1; + fdc_3f1_enable(0); + tries = 0; + } + else + { + tries++; + } + } + else + { + if (fdc37c932fr_locked) + { + if (val == 0xaa) + { + fdc37c932fr_locked = 0; + fdc_3f1_enable(1); + return; + } + fdc37c932fr_curreg = val; + } + else + { + if (tries) + tries = 0; + } + } + } + else + { + if (fdc37c932fr_locked) + { + if (fdc37c932fr_curreg < 48) + { + valxor = val ^ fdc37c932fr_regs[fdc37c932fr_curreg]; + fdc37c932fr_regs[fdc37c932fr_curreg] = val; + } + else + { + valxor = val ^ fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg]; + if ((fdc37c932fr_curreg & 0xF0 == 0x70) && (fdc37c932fr_regs[7] < 4)) return; + /* Block writes to IDE configuration. */ + if (fdc37c932fr_regs[7] == 1) return; + if (fdc37c932fr_regs[7] == 2) return; + if (fdc37c932fr_regs[7] > 5) return; + fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg] = val; + goto process_value; + } + } + } + return; + +process_value: + switch(fdc37c932fr_regs[7]) + { + case 0: + /* FDD */ + switch(fdc37c932fr_curreg) + { + case 0x30: + /* Activate */ + if (valxor) + { + if (!val) + fdc_remove(); + else + { + fdc_add(); + } + } + break; + case 0x60: + case 0x61: + if (valxor && fdc37c932fr_ld_regs[0][0x30]) + { + fdc_remove(); + ld_port = make_port(0); + fdc37c932fr_ld_regs[0][0x60] = make_port(0) >> 8; + fdc37c932fr_ld_regs[0][0x61] = make_port(0) & 0xFF; + fdc_add(); + } + break; + case 0xF0: + if (valxor & 0x01) fdc_update_enh_mode(val & 0x01); + if (valxor & 0x10) fdd_swap = ((val & 0x10) >> 4); + break; + case 0xF1: + if (valxor & 0xC) fdc_update_densel_force((val & 0xC) >> 2); + break; + case 0xF2: + if (valxor & 0x0C) fdc_update_rwc(1, (valxor & 0x0C) >> 2); + if (valxor & 0x03) fdc_update_rwc(0, (valxor & 0x03)); + break; + case 0xF4: + if (valxor & 0x18) fdc_update_drvrate(0, (val & 0x18) >> 3); + break; + case 0xF5: + if (valxor & 0x18) fdc_update_drvrate(1, (val & 0x18) >> 3); + break; + } + break; + case 3: + /* Parallel port */ + switch(fdc37c932fr_curreg) + { + case 0x30: + /* Activate */ + if (valxor) + { + if (!val) + lpt1_remove(); + else + { + ld_port = make_port(3); + lpt1_init(ld_port); + } + } + break; + case 0x60: + case 0x61: + if (valxor && fdc37c932fr_ld_regs[3][0x30]) + { + lpt1_remove(); + ld_port = make_port(3); + lpt1_init(ld_port); + } + break; + } + break; + case 4: + /* Serial port 1 */ + switch(fdc37c932fr_curreg) + { + case 0x30: + /* Activate */ + if (valxor) + { + if (!val) + serial1_remove(); + else + { + ld_port = make_port(4); + serial1_set(ld_port, fdc37c932fr_ld_regs[4][0x70]); + mouse_serial_init(); + } + } + break; + case 0x60: + case 0x61: + case 0x70: + if (valxor && fdc37c932fr_ld_regs[4][0x30]) + { + ld_port = make_port(4); + serial1_set(ld_port, fdc37c932fr_ld_regs[4][0x70]); + mouse_serial_init(); + } + break; + } + break; + case 5: + /* Serial port 2 */ + switch(fdc37c932fr_curreg) + { + case 0x30: + /* Activate */ + if (valxor) + { + if (!val) + serial2_remove(); + else + { + ld_port = make_port(5); + serial2_set(ld_port, fdc37c932fr_ld_regs[5][0x70]); + } + } + break; + case 0x60: + case 0x61: + case 0x70: + if (valxor && fdc37c932fr_ld_regs[5][0x30]) + { + ld_port = make_port(5); + serial2_set(ld_port, fdc37c932fr_ld_regs[5][0x70]); + } + break; + } + break; + } +} + +uint8_t fdc37c932fr_gpio_read(uint16_t port, void *priv) +{ + if (port & 1) + { + if (fdc37c932fr_gpio_curreg && (fdc37c932fr_gpio_curreg <= 0xF)) + return fdc37c932fr_gpio_regs[fdc37c932fr_gpio_curreg]; + else + return 0xff; + } + else + { + return fdc37c932fr_gpio_curreg; + } +} + +uint8_t fdc37c932fr_read(uint16_t port, void *priv) +{ + // pclog("fdc37c932fr_read : port=%04x reg %02X locked=%i\n", port, fdc37c932fr_curreg, fdc37c932fr_locked); + uint8_t index = (port & 1) ? 0 : 1; + + if (!fdc37c932fr_locked) + { + return 0xff; + } + + if (index) + return fdc37c932fr_curreg; + else + { + if (fdc37c932fr_curreg < 0x30) + { + // pclog("0x03F1: %02X\n", fdc37c932fr_regs[fdc37c932fr_curreg]); + return fdc37c932fr_regs[fdc37c932fr_curreg]; + } + else + { + // pclog("0x03F1 (CD=%02X): %02X\n", fdc37c932fr_regs[7], fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg]); + if ((fdc37c932fr_regs[7] == 0) && (fdc37c932fr_curreg == 0xF2)) return (fdc_get_rwc(0) | (fdc_get_rwc(1) << 2)); + return fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg]; + } + } +} + +void fdc37c932fr_init() +{ + int i = 0; + + lpt2_remove(); + + fdc37c932fr_regs[3] = 3; + fdc37c932fr_regs[0x20] = 3; + fdc37c932fr_regs[0x21] = 1; + fdc37c932fr_regs[0x24] = 4; + fdc37c932fr_regs[0x26] = 0xF0; + fdc37c932fr_regs[0x27] = 3; + + for (i = 0; i < 10; i++) + { + memset(fdc37c932fr_ld_regs[i], 0, 256); + } + + /* Logical device 0: FDD */ + fdc37c932fr_ld_regs[0][0x30] = 1; + fdc37c932fr_ld_regs[0][0x60] = 3; + fdc37c932fr_ld_regs[0][0x61] = 0xF0; + fdc37c932fr_ld_regs[0][0x70] = 6; + fdc37c932fr_ld_regs[0][0x74] = 2; + fdc37c932fr_ld_regs[0][0xF0] = 0xE; + fdc37c932fr_ld_regs[0][0xF2] = 0xFF; + + /* Logical device 1: IDE1 */ + fdc37c932fr_ld_regs[1][0x30] = 1; + fdc37c932fr_ld_regs[1][0x60] = 1; + fdc37c932fr_ld_regs[1][0x61] = 0xF0; + fdc37c932fr_ld_regs[1][0x62] = 3; + fdc37c932fr_ld_regs[1][0x63] = 0xF6; + fdc37c932fr_ld_regs[1][0x70] = 0xE; + fdc37c932fr_ld_regs[1][0xF0] = 0xC; + + /* Logical device 2: IDE2 */ + fdc37c932fr_ld_regs[2][0x30] = 1; + fdc37c932fr_ld_regs[2][0x60] = 1; + fdc37c932fr_ld_regs[2][0x61] = 0x70; + fdc37c932fr_ld_regs[2][0x62] = 3; + fdc37c932fr_ld_regs[2][0x63] = 0x76; + fdc37c932fr_ld_regs[2][0x70] = 0xF; + + /* Logical device 3: Parallel Port */ + fdc37c932fr_ld_regs[3][0x30] = 1; + fdc37c932fr_ld_regs[3][0x60] = 3; + fdc37c932fr_ld_regs[3][0x61] = 0x78; + fdc37c932fr_ld_regs[3][0x70] = 7; + fdc37c932fr_ld_regs[3][0x74] = 4; + fdc37c932fr_ld_regs[3][0xF0] = 0x3C; + + /* Logical device 4: Serial Port 1 */ + fdc37c932fr_ld_regs[4][0x30] = 1; + fdc37c932fr_ld_regs[4][0x60] = 3; + fdc37c932fr_ld_regs[4][0x61] = 0xf8; + fdc37c932fr_ld_regs[4][0x70] = 4; + fdc37c932fr_ld_regs[4][0xF0] = 3; + + /* Logical device 5: Serial Port 2 */ + fdc37c932fr_ld_regs[5][0x30] = 1; + fdc37c932fr_ld_regs[5][0x60] = 2; + fdc37c932fr_ld_regs[5][0x61] = 0xf8; + fdc37c932fr_ld_regs[5][0x70] = 3; + fdc37c932fr_ld_regs[5][0x74] = 4; + fdc37c932fr_ld_regs[5][0xF1] = 2; + fdc37c932fr_ld_regs[5][0xF2] = 3; + + /* Logical device 6: RTC */ + fdc37c932fr_ld_regs[6][0x63] = 0x70; + fdc37c932fr_ld_regs[6][0xF4] = 3; + + /* Logical device 7: Keyboard */ + fdc37c932fr_ld_regs[7][0x30] = 1; + fdc37c932fr_ld_regs[7][0x61] = 0x60; + fdc37c932fr_ld_regs[7][0x70] = 1; + + /* Logical device 8: AUX I/O */ + + /* Logical device 9: ACCESS.bus */ + + fdc_update_densel_force(0); + fdd_swap = 0; + fdc_update_rwc(0, 0); + fdc_update_rwc(1, 0); + fdc_update_drvrate(0, 0); + fdc_update_drvrate(1, 0); + io_sethandler(0xe0, 0x0006, fdc37c932fr_gpio_read, NULL, NULL, fdc37c932fr_gpio_write, NULL, NULL, NULL); + io_sethandler(0xea, 0x0002, fdc37c932fr_gpio_read, NULL, NULL, fdc37c932fr_gpio_write, NULL, NULL, NULL); + io_sethandler(0x3f0, 0x0002, fdc37c932fr_read, NULL, NULL, fdc37c932fr_write, NULL, NULL, NULL); + fdc37c932fr_locked = 0; +} diff --git a/src/fdc37c932fr.h b/src/fdc37c932fr.h new file mode 100644 index 000000000..8329d2ddd --- /dev/null +++ b/src/fdc37c932fr.h @@ -0,0 +1 @@ +extern void fdc37c932fr_init(); diff --git a/src/fdd.c b/src/fdd.c new file mode 100644 index 000000000..1237129da --- /dev/null +++ b/src/fdd.c @@ -0,0 +1,325 @@ +#include "ibm.h" +#include "disc.h" +#include "fdc.h" +#include "fdd.h" +#include "timer.h" + +static struct +{ + int type; + + int track; + + int densel; + + int drate; + + int kbps; + int fdc_kbps; + + int head; +} fdd[2]; + +/* Flags: + Bit 0: 300 rpm supported; + Bit 1: 360 rpm supported; + Bit 2: size (0 = 3.5", 1 = 5.25"); + Bit 3: double density supported; + Bit 4: high density supported; + Bit 5: extended density supported; + Bit 6: double step for 40-track media; +*/ +#define FLAG_RPM_300 1 +#define FLAG_RPM_360 2 +#define FLAG_525 4 +#define FLAG_HOLE0 8 +#define FLAG_HOLE1 16 +#define FLAG_HOLE2 32 +#define FLAG_DOUBLE_STEP 64 + +static struct +{ + int max_track; + int flags; +} drive_types[] = +{ + { /*None*/ + .max_track = 0, + .flags = 0 + }, + { /*5.25" DD*/ +#ifdef MAINLINE + .max_track = 41, +#else + .max_track = 43, +#endif + .flags = FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0 + }, + { /*5.25" HD*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_360 | FLAG_525 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP + }, + { /*5.25" HD Dual RPM*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP + }, + { /*3.5" DD*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_HOLE0 + }, + { /*3.5" HD*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_HOLE1 + }, + { /*3.5" HD 3-Mode*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_RPM_360 | FLAG_HOLE0 | FLAG_HOLE1 + }, + { /*3.5" ED*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 + } +}; + +int fdd_swap = 0; + +int fdd_stepping_motor_on[2] = {0, 0}; +int fdd_track_diff[2] = {0, 0}; +int fdd_track_direction[2] = {0, 0}; +int fdd_old_track[2] = {0, 0}; + +int fdd_poll_time[2] = {0, 0}; + +void fdd_seek_poll(int poll_drive) +{ + if (!fdd_track_diff[poll_drive]) + { + fdd_stepping_motor_on[poll_drive] = 0; + return; + } + + /* 80-track drive takes 6 µs per step, 40-track drive takes 10 µs. */ + // fdd_poll_time[poll_drive] += (drive_types[fdd[poll_drive].type].max_track <= 43) ? (10 * TIMER_USEC) : (6 * TIMER_USEC); + fdd_poll_time[poll_drive] += (drive_types[fdd[poll_drive].type].max_track <= 43) ? (5 * TIMER_USEC) : (3 * TIMER_USEC); + + if (fdd_track_direction[poll_drive]) + { + fdd[poll_drive].track++; + + if (fdd[poll_drive].track > drive_types[fdd[poll_drive].type].max_track) + fdd[poll_drive].track = drive_types[fdd[poll_drive].type].max_track; + } + else + { + fdd[poll_drive].track--; + + if (fdd[poll_drive].track < 0) + fdd[poll_drive].track = 0; + } + + fdd_track_diff[poll_drive]--; + + if (!fdd_track_diff[poll_drive]) + { + fdc_discchange_clear(poll_drive); + + disc_seek(poll_drive, fdd[poll_drive].track); + fdd_stepping_motor_on[poll_drive] = 0; + } +} + +void fdd_seek_poll_0() +{ + fdd_seek_poll(0); +} + +void fdd_seek_poll_1() +{ + fdd_seek_poll(1); +} + +#if 0 +void fdd_seek(int drive, int track_diff) +{ + drive ^= fdd_swap; + + fdd_old_track[drive] = fdd[drive].track; + + if (!track_diff) + { + /* Do not turn on motor if there are no pulses to be sent. */ + fdc_discchange_clear(drive); + return; + } + + fdd_stepping_motor_on[drive] = (track_diff == 0) ? 0 : 1; + if (fdd_stepping_motor_on[drive]) pclog("fdd_seek(): Stepping motor now on\n"); + + if (track_diff < 0) + { + fdd_track_diff[drive] = -track_diff; + fdd_track_direction[drive] = 0; + } + else + { + fdd_track_diff[drive] = track_diff; + fdd_track_direction[drive] = 1; + } + + fdd_old_track[drive] = fdd[drive].track; +} +#endif + +void fdd_seek(int drive, int track_diff) +{ + int old_track; + + drive ^= fdd_swap; + + old_track = fdd[drive].track; + + fdd[drive].track += track_diff; + + if (fdd[drive].track < 0) + fdd[drive].track = 0; + + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; + + // pclog("fdd_seek: drive=%i track_diff=%i old_track=%i track=%i\n", drive, track_diff, old_track, fdd[drive].track); + // if (fdd[drive].track != old_track) + // fdc_discchange_clear(drive); + fdc_discchange_clear(drive); + disc_seek(drive, fdd[drive].track); + // disctime = 5000; + disctime = 50; +} + +int fdd_track0(int drive) +{ + drive ^= fdd_swap; + + /* If drive is disabled, TRK0 never gets set. */ + if (!drive_types[fdd[drive].type].max_track) return 0; + + return !fdd[drive].track; +} + +void fdd_set_densel(int densel) +{ + fdd[0].densel = densel; + fdd[1].densel = densel; +} + +int fdd_getrpm(int drive) +{ + int hole = disc_hole(drive); + + drive ^= fdd_swap; + + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) return 300; + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) return 360; + + if (drive_types[fdd[drive].type].flags & FLAG_525) + { + return fdd[drive].densel ? 360 : 300; + } + else + { + /* disc_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */ + if (hole == 1) + { + return fdd[drive].densel ? 300 : 360; + } + else + { + return 300; + } + } +} + +void fdd_setswap(int swap) +{ + fdd_swap = swap ? 1 : 0; +} + +int fdd_can_read_medium(int drive) +{ + int hole = disc_hole(drive); + + drive ^= fdd_swap; + + hole = 1 << (hole + 3); + +// pclog("Drive %02X, type %02X, hole flag %02X, flags %02X, result %02X\n", drive, fdd[drive].type, hole, drive_types[fdd[drive].type].flags, drive_types[fdd[drive].type].flags & hole); + return (drive_types[fdd[drive].type].flags & hole) ? 1 : 0; +} + +int fdd_doublestep_40(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP; +} + +void fdd_set_type(int drive, int type) +{ + fdd[drive].type = type; +} + +int fdd_get_type(int drive) +{ + return fdd[drive].type; +} + +int fdd_is_525(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_525; +} + +int fdd_is_ed(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_HOLE2; +} + +void fdd_set_head(int drive, int head) +{ + drive ^= fdd_swap; + fdd[drive].head = head; +} + +int fdd_get_head(int drive) +{ + return fdd[drive].head; +} + +void fdd_init() +{ + fdd_stepping_motor_on[0] = fdd_stepping_motor_on[1] = 0; + fdd_track_diff[0] = fdd_track_diff[1] = 0; + + timer_add(fdd_seek_poll_0, &(fdd_poll_time[0]), &(fdd_stepping_motor_on[0]), NULL); + timer_add(fdd_seek_poll_1, &(fdd_poll_time[1]), &(fdd_stepping_motor_on[1]), NULL); +} diff --git a/src/fdd.h b/src/fdd.h new file mode 100644 index 000000000..8b183054e --- /dev/null +++ b/src/fdd.h @@ -0,0 +1,20 @@ +#define SEEK_RECALIBRATE -999 +void fdd_seek(int drive, int track_diff); +int fdd_track0(int drive); +int fdd_getrpm(int drive); +void fdd_set_densel(int densel); +int fdd_can_read_medium(int drive); +int fdd_doublestep_40(int drive); +int fdd_is_525(int drive); +int fdd_is_ed(int drive); +void fdd_set_head(int drive, int head); +int fdd_get_head(int drive); + +void fdd_set_type(int drive, int type); +int fdd_get_type(int drive); + +extern int fdd_swap; + +extern int fdd_stepping_motor_on[2]; +extern int fdd_track_diff[2]; +void fdd_init(); diff --git a/src/fdi2raw.c b/src/fdi2raw.c new file mode 100644 index 000000000..abace4f1b --- /dev/null +++ b/src/fdi2raw.c @@ -0,0 +1,2190 @@ +/* + + FDI to raw bit stream converter + Copyright (c) 2001 by Toni Wilen + FDI 2.0 support + Copyright (c) 2003-2004 by Toni Wilen + and Vincent Joguin + + FDI format created by Vincent "ApH" Joguin + + Tiny changes - function type fixes, multiple drives, addition of + get_last_head and C++ callability - by Thomas Harte, 2001, + T.Harte@excite.co.uk + + + 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 + +*/ + +#define STATIC_INLINE +#include +#include +#include +#include + +/* IF UAE */ +/*#include "sysconfig.h" +#include "sysdeps.h" +#include "zfile.h"*/ +/* ELSE */ +//#include "types.h" +#define xmalloc malloc +#include "fdi2raw.h" + +#include "ibm.h" + +#undef DEBUG +#define VERBOSE +#undef VERBOSE + +#include + +#ifdef DEBUG +static char *datalog(uae_u8 *src, int len) +{ + static char buf[1000]; + static int offset; + int i = 0, offset2; + + offset2 = offset; + buf[offset++]='\''; + while(len--) { + sprintf (buf + offset, "%02.2X", src[i]); + offset += 2; + i++; + if (i > 10) break; + } + buf[offset++]='\''; + buf[offset++] = 0; + if (offset >= 900) offset = 0; + return buf + offset2; +} +#else +static char *datalog(uae_u8 *src, int len) { return ""; } +#endif + +#define outlog pclog +#define debuglog pclog + +static int fdi_allocated; +#ifdef DEBUG +static void fdi_free (void *p) +{ + int size; + if (!p) + return; + size = ((int*)p)[-1]; + fdi_allocated -= size; + write_log ("%d freed (%d)\n", size, fdi_allocated); + free ((int*)p - 1); +} +static void *fdi_malloc (int size) +{ + void *p = xmalloc (size + sizeof (int)); + ((int*)p)[0] = size; + fdi_allocated += size; + write_log ("%d allocated (%d)\n", size, fdi_allocated); + return (int*)p + 1; +} +#else +#define fdi_free free +#define fdi_malloc xmalloc +#endif + +#define MAX_SRC_BUFFER 4194304 +#define MAX_DST_BUFFER 40000 +#define MAX_MFM_SYNC_BUFFER 60000 +#define MAX_TIMING_BUFFER 400000 +#define MAX_TRACKS 166 + +struct fdi_cache { + uae_u32 *avgp, *minp, *maxp; + uae_u8 *idxp; + int avg_free, idx_free, min_free, max_free; + uae_u32 totalavg, pulses, maxidx, indexoffset; + int weakbits; + int lowlevel; +}; + +struct fdi { + uae_u8 *track_src_buffer; + uae_u8 *track_src; + int track_src_len; + uae_u8 *track_dst_buffer; + uae_u8 *track_dst; + uae_u16 *track_dst_buffer_timing; + uae_u8 track_len; + uae_u8 track_type; + int current_track; + int last_track; + int last_head; + int rotation_speed; + int bit_rate; + int disk_type; + int write_protect; + int err; + uae_u8 header[2048]; + int track_offsets[MAX_TRACKS]; + FILE *file; + int out; + int mfmsync_offset; + int *mfmsync_buffer; + /* sector described only */ + int index_offset; + int encoding_type; + /* bit handling */ + int nextdrop; + struct fdi_cache cache[MAX_TRACKS]; +}; + +#define get_u32(x) ((((x)[0])<<24)|(((x)[1])<<16)|(((x)[2])<<8)|((x)[3])) +#define get_u24(x) ((((x)[0])<<16)|(((x)[1])<<8)|((x)[2])) +STATIC_INLINE void put_u32 (uae_u8 *d, uae_u32 v) +{ + d[0] = v >> 24; + d[1] = v >> 16; + d[2] = v >> 8; + d[3] = v; +} + +struct node { + uae_u16 v; + struct node *left; + struct node *right; +}; +typedef struct node NODE; + +static uae_u8 temp, temp2; + +static uae_u8 *expand_tree (uae_u8 *stream, NODE *node) +{ + if (temp & temp2) { + fdi_free (node->left); + node->left = 0; + fdi_free (node->right); + node->right = 0; + temp2 >>= 1; + if (!temp2) { + temp = *stream++; + temp2 = 0x80; + } + return stream; + } else { + uae_u8 *stream_temp; + temp2 >>= 1; + if (!temp2) { + temp = *stream++; + temp2 = 0x80; + } + node->left = fdi_malloc (sizeof (NODE)); + memset (node->left, 0, sizeof (NODE)); + stream_temp = expand_tree (stream, node->left); + node->right = fdi_malloc (sizeof (NODE)); + memset (node->right, 0, sizeof (NODE)); + return expand_tree (stream_temp, node->right); + } +} + +static uae_u8 *values_tree8 (uae_u8 *stream, NODE *node) +{ + if (node->left == 0) { + node->v = *stream++; + return stream; + } else { + uae_u8 *stream_temp = values_tree8 (stream, node->left); + return values_tree8 (stream_temp, node->right); + } +} + +static uae_u8 *values_tree16 (uae_u8 *stream, NODE *node) +{ + if (node->left == 0) { + uae_u16 high_8_bits = (*stream++) << 8; + node->v = high_8_bits | (*stream++); + return stream; + } else { + uae_u8 *stream_temp = values_tree16 (stream, node->left); + return values_tree16 (stream_temp, node->right); + } +} + +static void free_nodes (NODE *node) +{ + if (node) { + free_nodes (node->left); + free_nodes (node->right); + fdi_free (node); + } +} + +static uae_u32 sign_extend16 (uae_u32 v) +{ + if (v & 0x8000) + v |= 0xffff0000; + return v; +} + +static uae_u32 sign_extend8 (uae_u32 v) +{ + if (v & 0x80) + v |= 0xffffff00; + return v; +} + +static void fdi_decode (uae_u8 *stream, int size, uae_u8 *out) +{ + int i; + uae_u8 sign_extend, sixteen_bit, sub_stream_shift; + NODE root; + NODE *current_node; + + memset (out, 0, size * 4); + sub_stream_shift = 1; + while (sub_stream_shift) { + + //sub-stream header decode + sign_extend = *stream++; + sub_stream_shift = sign_extend & 0x7f; + sign_extend &= 0x80; + sixteen_bit = (*stream++) & 0x80; + + //huffman tree architecture decode + temp = *stream++; + temp2 = 0x80; + stream = expand_tree (stream, &root); + if (temp2 == 0x80) + stream--; + + //huffman output values decode + if (sixteen_bit) + stream = values_tree16 (stream, &root); + else + stream = values_tree8 (stream, &root); + + //sub-stream data decode + temp2 = 0; + for (i = 0; i < size; i++) { + uae_u32 v; + uae_u8 decode = 1; + current_node = &root; + while (decode) { + if (current_node->left == 0) { + decode = 0; + } else { + temp2 >>= 1; + if (!temp2) { + temp2 = 0x80; + temp = *stream++; + } + if (temp & temp2) + current_node = current_node->right; + else + current_node = current_node->left; + } + } + v = ((uae_u32*)out)[i]; + if (sign_extend) { + if (sixteen_bit) + v |= sign_extend16 (current_node->v) << sub_stream_shift; + else + v |= sign_extend8 (current_node->v) << sub_stream_shift; + } else { + v |= current_node->v << sub_stream_shift; + } + ((uae_u32*)out)[i] = v; + } + free_nodes (root.left); + free_nodes (root.right); + } +} + + +static int decode_raw_track (FDI *fdi) +{ + int size = get_u32(fdi->track_src); + memcpy (fdi->track_dst, fdi->track_src, (size + 7) >> 3); + fdi->track_src += (size + 7) >> 3; + return size; +} + +/* unknown track */ +static void zxx (FDI *fdi) +{ + outlog ("track %d: unknown track type 0x%02.2X\n", fdi->current_track, fdi->track_type); +// return -1; +} +/* unsupported track */ +#if 0 +static void zyy (FDI *fdi) +{ + outlog ("track %d: unsupported track type 0x%02.2X\n", fdi->current_track, fdi->track_type); +// return -1; +} +#endif +/* empty track */ +static void track_empty (FDI *fdi) +{ +// return 0; +} + +/* unknown sector described type */ +static void dxx (FDI *fdi) +{ + outlog ("\ntrack %d: unknown sector described type 0x%02.2X\n", fdi->current_track, fdi->track_type); + fdi->err = 1; +} +/* unsupported sector described type */ +#if 0 +static void dyy (FDI *fdi) +{ + outlog ("\ntrack %d: unsupported sector described 0x%02.2X\n", fdi->current_track, fdi->track_type); + fdi->err = 1; +} +#endif +/* add position of mfm sync bit */ +static void add_mfm_sync_bit (FDI *fdi) +{ + if (fdi->nextdrop) { + fdi->nextdrop = 0; + return; + } + fdi->mfmsync_buffer[fdi->mfmsync_offset++] = fdi->out; + if (fdi->out == 0) { + outlog ("illegal position for mfm sync bit, offset=%d\n",fdi->out); + fdi->err = 1; + } + if (fdi->mfmsync_offset >= MAX_MFM_SYNC_BUFFER) { + fdi->mfmsync_offset = 0; + outlog ("mfmsync buffer overflow\n"); + fdi->err = 1; + } + fdi->out++; +} + +#define BIT_BYTEOFFSET ((fdi->out) >> 3) +#define BIT_BITOFFSET (7-((fdi->out)&7)) + +/* add one bit */ +static void bit_add (FDI *fdi, int bit) +{ + if (fdi->nextdrop) { + fdi->nextdrop = 0; + return; + } + fdi->track_dst[BIT_BYTEOFFSET] &= ~(1 << BIT_BITOFFSET); + if (bit) + fdi->track_dst[BIT_BYTEOFFSET] |= (1 << BIT_BITOFFSET); + fdi->out++; + if (fdi->out >= MAX_DST_BUFFER * 8) { + outlog ("destination buffer overflow\n"); + fdi->err = 1; + fdi->out = 1; + } +} +/* add bit and mfm sync bit */ +static void bit_mfm_add (FDI *fdi, int bit) +{ + add_mfm_sync_bit (fdi); + bit_add (fdi, bit); +} +/* remove following bit */ +static void bit_drop_next (FDI *fdi) +{ + if (fdi->nextdrop > 0) { + outlog("multiple bit_drop_next() called"); + } else if (fdi->nextdrop < 0) { + fdi->nextdrop = 0; + debuglog(":DNN:"); + return; + } + debuglog(":DN:"); + fdi->nextdrop = 1; +} + +/* ignore next bit_drop_next() */ +static void bit_dedrop (FDI *fdi) +{ + if (fdi->nextdrop) { + outlog("bit_drop_next called before bit_dedrop"); + } + fdi->nextdrop = -1; + debuglog(":BDD:"); +} + +/* add one byte */ +static void byte_add (FDI *fdi, uae_u8 v) +{ + int i; + for (i = 7; i >= 0; i--) + bit_add (fdi, v & (1 << i)); +} +/* add one word */ +static void word_add (FDI *fdi, uae_u16 v) +{ + byte_add (fdi, (uae_u8)(v >> 8)); + byte_add (fdi, (uae_u8)v); +} +/* add one byte and mfm encode it */ +static void byte_mfm_add (FDI *fdi, uae_u8 v) +{ + int i; + for (i = 7; i >= 0; i--) + bit_mfm_add (fdi, v & (1 << i)); +} +/* add multiple bytes and mfm encode them */ +static void bytes_mfm_add (FDI *fdi, uae_u8 v, int len) +{ + int i; + for (i = 0; i < len; i++) byte_mfm_add (fdi, v); +} +/* add one mfm encoded word and re-mfm encode it */ +static void word_post_mfm_add (FDI *fdi, uae_u16 v) +{ + int i; + for (i = 14; i >= 0; i -= 2) + bit_mfm_add (fdi, v & (1 << i)); +} + +/* bit 0 */ +static void s00(FDI *fdi) { bit_add (fdi, 0); } +/* bit 1*/ +static void s01(FDI *fdi) { bit_add (fdi, 1); } +/* 4489 */ +static void s02(FDI *fdi) { word_add (fdi, 0x4489); } +/* 5224 */ +static void s03(FDI *fdi) { word_add (fdi, 0x5224); } +/* mfm sync bit */ +static void s04(FDI *fdi) { add_mfm_sync_bit (fdi); } +/* RLE MFM-encoded data */ +static void s08(FDI *fdi) +{ + int bytes = *fdi->track_src++; + uae_u8 byte = *fdi->track_src++; + if (bytes == 0) bytes = 256; + debuglog ("s08:len=%d,data=%02.2X",bytes,byte); + while(bytes--) byte_add (fdi, byte); +} +/* RLE MFM-decoded data */ +static void s09(FDI *fdi) +{ + int bytes = *fdi->track_src++; + uae_u8 byte = *fdi->track_src++; + if (bytes == 0) bytes = 256; + bit_drop_next (fdi); + debuglog ("s09:len=%d,data=%02.2X",bytes,byte); + while(bytes--) byte_mfm_add (fdi, byte); +} +/* MFM-encoded data */ +static void s0a(FDI *fdi) +{ + int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1]; + uae_u8 b; + fdi->track_src += 2; + debuglog ("s0a:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while (bits--) { + bit_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-encoded data */ +static void s0b(FDI *fdi) +{ + int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536; + uae_u8 b; + fdi->track_src += 2; + debuglog ("s0b:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while (bits--) { + bit_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-decoded data */ +static void s0c(FDI *fdi) +{ + int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1]; + uae_u8 b; + fdi->track_src += 2; + bit_drop_next (fdi); + debuglog ("s0c:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_mfm_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while(bits--) { + bit_mfm_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-decoded data */ +static void s0d(FDI *fdi) +{ + int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536; + uae_u8 b; + fdi->track_src += 2; + bit_drop_next (fdi); + debuglog ("s0d:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_mfm_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while(bits--) { + bit_mfm_add (fdi, b & (1 << i)); + i--; + } + } +} + +/* ***** */ +/* AMIGA */ +/* ***** */ + +/* just for testing integrity of Amiga sectors */ + +/*static void rotateonebit (uae_u8 *start, uae_u8 *end, int shift) +{ + if (shift == 0) + return; + while (start <= end) { + start[0] <<= shift; + start[0] |= start[1] >> (8 - shift); + start++; + } +}*/ + +//static int check_offset; +/*static uae_u16 getmfmword (uae_u8 *mbuf) +{ + uae_u32 v; + + v = (mbuf[0] << 8) | (mbuf[1] << 0); + if (check_offset == 0) + return v; + v <<= 8; + v |= mbuf[2]; + v >>= check_offset; + return v; +}*/ + +#define MFMMASK 0x55555555 +/*static uae_u32 getmfmlong (uae_u8 * mbuf) +{ + return ((getmfmword (mbuf) << 16) | getmfmword (mbuf + 2)) & MFMMASK; +}*/ + +#if 0 +static int amiga_check_track (FDI *fdi) +{ + int i, j, secwritten = 0; + int fwlen = fdi->out / 8; + int length = 2 * fwlen; + int drvsec = 11; + uae_u32 odd, even, chksum, id, dlong; + uae_u8 *secdata; + uae_u8 secbuf[544]; + uae_u8 bigmfmbuf[60000]; + uae_u8 *mbuf, *mbuf2, *mend; + char sectable[22]; + uae_u8 *raw = fdi->track_dst_buffer; + int slabel, off; + int ok = 1; + + memset (bigmfmbuf, 0, sizeof (bigmfmbuf)); + mbuf = bigmfmbuf; + check_offset = 0; + for (i = 0; i < (fdi->out + 7) / 8; i++) + *mbuf++ = raw[i]; + off = fdi->out & 7; +#if 1 + if (off > 0) { + mbuf--; + *mbuf &= ~((1 << (8 - off)) - 1); + } + j = 0; + while (i < (fdi->out + 7) / 8 + 600) { + *mbuf++ |= (raw[j] >> off) | ((raw[j + 1]) << (8 - off)); + j++; + i++; + } +#endif + mbuf = bigmfmbuf; + + memset (sectable, 0, sizeof (sectable)); + //memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16)); + mend = bigmfmbuf + length; + mend -= (4 + 16 + 8 + 512); + + while (secwritten < drvsec) { + int trackoffs; + + for (;;) { + rotateonebit (bigmfmbuf, mend, 1); + if (getmfmword (mbuf) == 0) + break; + if (secwritten == 10) { + mbuf[0] = 0x44; + mbuf[1] = 0x89; + } +// check_offset++; + if (check_offset > 7) { + check_offset = 0; + mbuf++; + if (mbuf >= mend || *mbuf == 0) + break; + } + if (getmfmword (mbuf) == 0x4489) + break; + } + if (mbuf >= mend || *mbuf == 0) + break; + + rotateonebit (bigmfmbuf, mend, check_offset); + check_offset = 0; + + while (getmfmword (mbuf) == 0x4489) + mbuf+= 1 * 2; + mbuf2 = mbuf + 8; + + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + id = (odd << 1) | even; + + trackoffs = (id & 0xff00) >> 8; + if (trackoffs + 1 > drvsec) { + outlog("illegal sector offset %d\n",trackoffs); + ok = 0; + mbuf = mbuf2; + continue; + } + if ((id >> 24) != 0xff) { + outlog ("sector %d format type %02.2X?\n", trackoffs, id >> 24); + ok = 0; + } + chksum = odd ^ even; + slabel = 0; + for (i = 0; i < 4; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 8 * 2); + mbuf += 2* 2; + + dlong = (odd << 1) | even; + if (dlong) slabel = 1; + chksum ^= odd ^ even; + } + mbuf += 8 * 2; + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + if (((odd << 1) | even) != chksum) { + outlog("sector %d header crc error\n", trackoffs); + ok = 0; + mbuf = mbuf2; + continue; + } + outlog("sector %d header crc ok\n", trackoffs); + if (((id & 0x00ff0000) >> 16) != (uae_u32)fdi->current_track) { + outlog("illegal track number %d <> %d\n",fdi->current_track,(id & 0x00ff0000) >> 16); + ok++; + mbuf = mbuf2; + continue; + } + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + chksum = (odd << 1) | even; + secdata = secbuf + 32; + for (i = 0; i < 128; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 256 * 2); + mbuf += 2 * 2; + dlong = (odd << 1) | even; + *secdata++ = (uae_u8) (dlong >> 24); + *secdata++ = (uae_u8) (dlong >> 16); + *secdata++ = (uae_u8) (dlong >> 8); + *secdata++ = (uae_u8) dlong; + chksum ^= odd ^ even; + } + mbuf += 256 * 2; + if (chksum) { + outlog("sector %d data checksum error\n",trackoffs); + ok = 0; + } else if (sectable[trackoffs]) { + outlog("sector %d already found?\n", trackoffs); + mbuf = mbuf2; + } else { + outlog("sector %d ok\n",trackoffs); + if (slabel) outlog("(non-empty sector header)\n"); + sectable[trackoffs] = 1; + secwritten++; + if (trackoffs == 9) + mbuf += 0x228; + } + } + for (i = 0; i < drvsec; i++) { + if (!sectable[i]) { + outlog ("sector %d missing\n", i); + ok = 0; + } + } + return ok; +} +#endif + +static void amiga_data_raw (FDI *fdi, uae_u8 *secbuf, uae_u8 *crc, int len) +{ + int i; + uae_u8 crcbuf[4]; + + if (!crc) { + memset (crcbuf, 0, 4); + } else { + memcpy (crcbuf, crc ,4); + } + for (i = 0; i < 4; i++) + byte_mfm_add (fdi, crcbuf[i]); + for (i = 0; i < len; i++) + byte_mfm_add (fdi, secbuf[i]); +} + +static void amiga_data (FDI *fdi, uae_u8 *secbuf) +{ + uae_u16 mfmbuf[4 + 512]; + uae_u32 dodd, deven, dck; + int i; + + for (i = 0; i < 512; i += 4) { + deven = ((secbuf[i + 0] << 24) | (secbuf[i + 1] << 16) + | (secbuf[i + 2] << 8) | (secbuf[i + 3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 4] = (uae_u16) (dodd >> 16); + mfmbuf[(i >> 1) + 5] = (uae_u16) dodd; + mfmbuf[(i >> 1) + 256 + 4] = (uae_u16) (deven >> 16); + mfmbuf[(i >> 1) + 256 + 5] = (uae_u16) deven; + } + dck = 0; + for (i = 4; i < 4 + 512; i += 2) + dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + deven = dodd = dck; + dodd >>= 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[0] = (uae_u16) (dodd >> 16); + mfmbuf[1] = (uae_u16) dodd; + mfmbuf[2] = (uae_u16) (deven >> 16); + mfmbuf[3] = (uae_u16) deven; + + for (i = 0; i < 4 + 512; i ++) + word_post_mfm_add (fdi, mfmbuf[i]); +} + +static void amiga_sector_header (FDI *fdi, uae_u8 *header, uae_u8 *data, int sector, int untilgap) +{ + uae_u8 headerbuf[4], databuf[16]; + uae_u32 deven, dodd, hck; + uae_u16 mfmbuf[24]; + int i; + + byte_mfm_add (fdi, 0); + byte_mfm_add (fdi, 0); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + if (header) { + memcpy (headerbuf, header, 4); + } else { + headerbuf[0] = 0xff; + headerbuf[1] = (uae_u8)fdi->current_track; + headerbuf[2] = (uae_u8)sector; + headerbuf[3] = (uae_u8)untilgap; + } + if (data) + memcpy (databuf, data, 16); + else + memset (databuf, 0, 16); + + deven = ((headerbuf[0] << 24) | (headerbuf[1] << 16) + | (headerbuf[2] << 8) | (headerbuf[3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[0] = (uae_u16) (dodd >> 16); + mfmbuf[1] = (uae_u16) dodd; + mfmbuf[2] = (uae_u16) (deven >> 16); + mfmbuf[3] = (uae_u16) deven; + for (i = 0; i < 16; i += 4) { + deven = ((databuf[i] << 24) | (databuf[i + 1] << 16) + | (databuf[i + 2] << 8) | (databuf[i + 3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 0 + 4] = (uae_u16) (dodd >> 16); + mfmbuf[(i >> 1) + 0 + 5] = (uae_u16) dodd; + mfmbuf[(i >> 1) + 8 + 4] = (uae_u16) (deven >> 16); + mfmbuf[(i >> 1) + 8 + 5] = (uae_u16) deven; + } + hck = 0; + for (i = 0; i < 4 + 16; i += 2) + hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + deven = dodd = hck; + dodd >>= 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[20] = (uae_u16) (dodd >> 16); + mfmbuf[21] = (uae_u16) dodd; + mfmbuf[22] = (uae_u16) (deven >> 16); + mfmbuf[23] = (uae_u16) deven; + + for (i = 0; i < 4 + 16 + 4; i ++) + word_post_mfm_add (fdi, mfmbuf[i]); +} + +/* standard super-extended Amiga sector header */ +static void s20(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s20:header=%s,data=%s", datalog(fdi->track_src, 4), datalog(fdi->track_src + 4, 16)); + amiga_sector_header (fdi, fdi->track_src, fdi->track_src + 4, 0, 0); + fdi->track_src += 4 + 16; +} +/* standard extended Amiga sector header */ +static void s21(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s21:header=%s", datalog(fdi->track_src, 4)); + amiga_sector_header (fdi, fdi->track_src, 0, 0, 0); + fdi->track_src += 4; +} +/* standard Amiga sector header */ +static void s22(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog("s22:sector=%d,untilgap=%d", fdi->track_src[0], fdi->track_src[1]); + amiga_sector_header (fdi, 0, 0, fdi->track_src[0], fdi->track_src[1]); + fdi->track_src += 2; +} +/* standard 512-byte, CRC-correct Amiga data */ +static void s23(FDI *fdi) +{ + debuglog("s23:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} +/* not-decoded, 128*2^x-byte, CRC-correct Amiga data */ +static void s24(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog("s24:shift=%d,data=%s", shift, datalog (fdi->track_src, 128 << shift)); + amiga_data_raw (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* not-decoded, 128*2^x-byte, CRC-incorrect Amiga data */ +static void s25(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog("s25:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 128 << shift)); + amiga_data_raw (fdi, fdi->track_src + 4, fdi->track_src, 128 << shift); + fdi->track_src += 4 + (128 << shift); +} +/* standard extended Amiga sector */ +static void s26(FDI *fdi) +{ + s21 (fdi); + debuglog("s26:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} +/* standard short Amiga sector */ +static void s27(FDI *fdi) +{ + s22 (fdi); + debuglog("s27:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} + +/* *** */ +/* IBM */ +/* *** */ + +static uae_u16 ibm_crc (uae_u8 byte, int reset) +{ + static uae_u16 crc; + int i; + + if (reset) crc = 0xcdb4; + for (i = 0; i < 8; i++) { + if (crc & 0x8000) { + crc <<= 1; + if (!(byte & 0x80)) crc ^= 0x1021; + } else { + crc <<= 1; + if (byte & 0x80) crc ^= 0x1021; + } + byte <<= 1; + } + return crc; +} + +static void ibm_data (FDI *fdi, uae_u8 *data, uae_u8 *crc, int len) +{ + int i; + uae_u8 crcbuf[2]; + uae_u16 crcv = 0; + + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + byte_mfm_add (fdi, 0xfb); + ibm_crc (0xfb, 1); + for (i = 0; i < len; i++) { + byte_mfm_add (fdi, data[i]); + crcv = ibm_crc (data[i], 0); + } + if (!crc) { + crc = crcbuf; + crc[0] = (uae_u8)(crcv >> 8); + crc[1] = (uae_u8)crcv; + } + byte_mfm_add (fdi, crc[0]); + byte_mfm_add (fdi, crc[1]); +} + +static void ibm_sector_header (FDI *fdi, uae_u8 *data, uae_u8 *crc, int secnum, int pre) +{ + uae_u8 secbuf[5]; + uae_u8 crcbuf[2]; + uae_u16 crcv; + int i; + + if (pre) + bytes_mfm_add (fdi, 0, 12); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + secbuf[0] = 0xfe; + if (secnum >= 0) { + secbuf[1] = (uae_u8)(fdi->current_track/2); + secbuf[2] = (uae_u8)(fdi->current_track%2); + secbuf[3] = (uae_u8)secnum; + secbuf[4] = 2; + } else { + memcpy (secbuf + 1, data, 4); + } + ibm_crc (secbuf[0], 1); + ibm_crc (secbuf[1], 0); + ibm_crc (secbuf[2], 0); + ibm_crc (secbuf[3], 0); + crcv = ibm_crc (secbuf[4], 0); + if (crc) { + memcpy (crcbuf, crc, 2); + } else { + crcbuf[0] = (uae_u8)(crcv >> 8); + crcbuf[1] = (uae_u8)crcv; + } + /* data */ + for (i = 0;i < 5; i++) + byte_mfm_add (fdi, secbuf[i]); + /* crc */ + byte_mfm_add (fdi, crcbuf[0]); + byte_mfm_add (fdi, crcbuf[1]); +} + +/* standard IBM index address mark */ +static void s10(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0, 12); + word_add (fdi, 0x5224); + word_add (fdi, 0x5224); + word_add (fdi, 0x5224); + byte_mfm_add (fdi, 0xfc); +} +/* standard IBM pre-gap */ +static void s11(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0x4e, 78); + bit_dedrop (fdi); + s10 (fdi); + bytes_mfm_add (fdi, 0x4e, 50); +} +/* standard ST pre-gap */ +static void s12(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0x4e, 78); +} +/* standard extended IBM sector header */ +static void s13(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s13:header=%s", datalog (fdi->track_src, 4)); + ibm_sector_header (fdi, fdi->track_src, 0, -1, 1); + fdi->track_src += 4; +} +/* standard mini-extended IBM sector header */ +static void s14(FDI *fdi) +{ + debuglog ("s14:header=%s", datalog (fdi->track_src, 4)); + ibm_sector_header (fdi, fdi->track_src, 0, -1, 0); + fdi->track_src += 4; +} +/* standard short IBM sector header */ +static void s15(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s15:sector=%d", *fdi->track_src); + ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 1); +} +/* standard mini-short IBM sector header */ +static void s16(FDI *fdi) +{ + debuglog ("s16:track=%d", *fdi->track_src); + ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 0); +} +/* standard CRC-incorrect mini-extended IBM sector header */ +static void s17(FDI *fdi) +{ + debuglog ("s17:header=%s,crc=%s", datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 2)); + ibm_sector_header (fdi, fdi->track_src, fdi->track_src + 4, -1, 0); + fdi->track_src += 4 + 2; +} +/* standard CRC-incorrect mini-short IBM sector header */ +static void s18(FDI *fdi) +{ + debuglog ("s18:sector=%d,header=%s", *fdi->track_src, datalog (fdi->track_src + 1, 4)); + ibm_sector_header (fdi, 0, fdi->track_src + 1, *fdi->track_src, 0); + fdi->track_src += 1 + 4; +} +/* standard 512-byte CRC-correct IBM data */ +static void s19(FDI *fdi) +{ + debuglog ("s19:data=%s", datalog (fdi->track_src , 512)); + ibm_data (fdi, fdi->track_src, 0, 512); + fdi->track_src += 512; +} +/* standard 128*2^x-byte-byte CRC-correct IBM data */ +static void s1a(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog ("s1a:shift=%d,data=%s", shift, datalog (fdi->track_src , 128 << shift)); + ibm_data (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* standard 128*2^x-byte-byte CRC-incorrect IBM data */ +static void s1b(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog ("s1b:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src + (128 << shift), 2), datalog (fdi->track_src , 128 << shift)); + ibm_data (fdi, fdi->track_src, fdi->track_src + (128 << shift), 128 << shift); + fdi->track_src += (128 << shift) + 2; +} +/* standard extended IBM sector */ +static void s1c(FDI *fdi) +{ + int shift = fdi->track_src[3]; + s13 (fdi); + bytes_mfm_add (fdi, 0x4e, 22); + bytes_mfm_add (fdi, 0x00, 12); + ibm_data (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* standard short IBM sector */ +static void s1d(FDI *fdi) +{ + s15 (fdi); + bytes_mfm_add (fdi, 0x4e, 22); + bytes_mfm_add (fdi, 0x00, 12); + s19 (fdi); +} + +/* end marker */ +static void sff(FDI *fdi) +{ +} + +typedef void (*decode_described_track_func)(FDI*); + +static decode_described_track_func decode_sectors_described_track[] = +{ + s00,s01,s02,s03,s04,dxx,dxx,dxx,s08,s09,s0a,s0b,s0c,s0d,dxx,dxx, /* 00-0F */ + s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s1a,s1b,s1c,s1d,dxx,dxx, /* 10-1F */ + s20,s21,s22,s23,s24,s25,s26,s27,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 20-2F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 30-3F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 40-4F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 50-5F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 60-6F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 70-7F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 80-8F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 90-9F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* A0-AF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* B0-BF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* C0-CF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* D0-DF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* E0-EF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,sff /* F0-FF */ +}; + +static void track_amiga (struct fdi *fdi, int first_sector, int max_sector) +{ + int i; + + bit_add (fdi, 0); + bit_drop_next (fdi); + for (i = 0; i < max_sector; i++) { + amiga_sector_header (fdi, 0, 0, first_sector, max_sector - i); + amiga_data (fdi, fdi->track_src + first_sector * 512); + first_sector++; + if (first_sector >= max_sector) first_sector = 0; + } + bytes_mfm_add (fdi, 0, 260); /* gap */ +} +static void track_atari_st (struct fdi *fdi, int max_sector) +{ + int i, gap3 = 0; + uae_u8 *p = fdi->track_src; + + switch (max_sector) + { + case 9: + gap3 = 40; + break; + case 10: + gap3 = 24; + break; + } + s15 (fdi); + for (i = 0; i < max_sector; i++) { + byte_mfm_add (fdi, 0x4e); + byte_mfm_add (fdi, 0x4e); + ibm_sector_header (fdi, 0, 0, fdi->current_track, 1); + ibm_data (fdi, p + i * 512, 0, 512); + bytes_mfm_add (fdi, 0x4e, gap3); + } + bytes_mfm_add (fdi, 0x4e, 660 - gap3); + fdi->track_src += fdi->track_len * 256; +} +static void track_pc (struct fdi *fdi, int max_sector) +{ + int i, gap3; + uae_u8 *p = fdi->track_src; + + switch (max_sector) + { + case 8: + gap3 = 116; + break; + case 9: + gap3 = 54; + break; + default: + gap3 = 100; /* fixme */ + break; + } + s11 (fdi); + for (i = 0; i < max_sector; i++) { + byte_mfm_add (fdi, 0x4e); + byte_mfm_add (fdi, 0x4e); + ibm_sector_header (fdi, 0, 0, fdi->current_track, 1); + ibm_data (fdi, p + i * 512, 0, 512); + bytes_mfm_add (fdi, 0x4e, gap3); + } + bytes_mfm_add (fdi, 0x4e, 600 - gap3); + fdi->track_src += fdi->track_len * 256; +} + +/* amiga dd */ +static void track_amiga_dd (struct fdi *fdi) +{ + uae_u8 *p = fdi->track_src; + track_amiga (fdi, fdi->track_len >> 4, 11); + fdi->track_src = p + (fdi->track_len & 15) * 512; +} +/* amiga hd */ +static void track_amiga_hd (struct fdi *fdi) +{ + uae_u8 *p = fdi->track_src; + track_amiga (fdi, 0, 22); + fdi->track_src = p + fdi->track_len * 256; +} +/* atari st 9 sector */ +static void track_atari_st_9 (struct fdi *fdi) +{ + track_atari_st (fdi, 9); +} +/* atari st 10 sector */ +static void track_atari_st_10 (struct fdi *fdi) +{ + track_atari_st (fdi, 10); +} +/* pc 8 sector */ +static void track_pc_8 (struct fdi *fdi) +{ + track_pc (fdi, 8); +} +/* pc 9 sector */ +static void track_pc_9 (struct fdi *fdi) +{ + track_pc (fdi, 9); +} +/* pc 15 sector */ +static void track_pc_15 (struct fdi *fdi) +{ + track_pc (fdi, 15); +} +/* pc 18 sector */ +static void track_pc_18 (struct fdi *fdi) +{ + track_pc (fdi, 18); +} +/* pc 36 sector */ +static void track_pc_36 (struct fdi *fdi) +{ + track_pc (fdi, 36); +} + +typedef void (*decode_normal_track_func)(FDI*); + +static decode_normal_track_func decode_normal_track[] = +{ + track_empty, /* 0 */ + track_amiga_dd, track_amiga_hd, /* 1-2 */ + track_atari_st_9, track_atari_st_10, /* 3-4 */ + track_pc_8, track_pc_9, track_pc_15, track_pc_18, track_pc_36, /* 5-9 */ + zxx,zxx,zxx,zxx,zxx /* A-F */ +}; + +static void fix_mfm_sync (FDI *fdi) +{ + int i, pos, off1, off2, off3, mask1, mask2, mask3; + + for (i = 0; i < fdi->mfmsync_offset; i++) { + pos = fdi->mfmsync_buffer[i]; + off1 = (pos - 1) >> 3; + off2 = (pos + 1) >> 3; + off3 = pos >> 3; + mask1 = 1 << (7 - ((pos - 1) & 7)); + mask2 = 1 << (7 - ((pos + 1) & 7)); + mask3 = 1 << (7 - (pos & 7)); + if (!(fdi->track_dst[off1] & mask1) && !(fdi->track_dst[off2] & mask2)) + fdi->track_dst[off3] |= mask3; + else + fdi->track_dst[off3] &= ~mask3; + } +} + +static int handle_sectors_described_track (FDI *fdi) +{ + int oldout; + uae_u8 *start_src = fdi->track_src ; + fdi->encoding_type = *fdi->track_src++; + fdi->index_offset = get_u32(fdi->track_src); + fdi->index_offset >>= 8; + fdi->track_src += 3; + outlog ("sectors_described, index offset: %d\n",fdi->index_offset); + + do { + fdi->track_type = *fdi->track_src++; + outlog ("%06.6X %06.6X %02.2X:",fdi->track_src - start_src + 0x200, fdi->out/8, fdi->track_type); + oldout = fdi->out; + decode_sectors_described_track[fdi->track_type](fdi); + outlog(" %d\n", fdi->out - oldout); + oldout = fdi->out; + if (fdi->out < 0 || fdi->err) { + outlog ("\nin %d bytes, out %d bits\n", fdi->track_src - fdi->track_src_buffer, fdi->out); + return -1; + } + if (fdi->track_src - fdi->track_src_buffer >= fdi->track_src_len) { + outlog ("source buffer overrun, previous type: %02.2X\n", fdi->track_type); + return -1; + } + } while (fdi->track_type != 0xff); + outlog("\n"); + fix_mfm_sync (fdi); + return fdi->out; +} + +static uae_u8 *fdi_decompress (int pulses, uae_u8 *sizep, uae_u8 *src, int *dofree) +{ + uae_u32 size = get_u24 (sizep); + uae_u32 *dst2; + int len = size & 0x3fffff; + uae_u8 *dst; + int mode = size >> 22, i; + + *dofree = 0; + if (mode == 0 && pulses * 2 > len) + mode = 1; + if (mode == 0) { + dst2 = (uae_u32*)src; + dst = src; + for (i = 0; i < pulses; i++) { + *dst2++ = get_u32 (src); + src += 4; + } + } else if (mode == 1) { + dst = fdi_malloc (pulses *4); + *dofree = 1; + fdi_decode (src, pulses, dst); + } else { + dst = 0; + } + return dst; +} + +static void dumpstream(int track, uae_u8 *stream, int len) +{ +#if 0 + char name[100]; + FILE *f; + + sprintf (name, "track_%d.raw", track); + f = fopen(name, "wb"); + fwrite (stream, 1, len * 4, f); + fclose (f); +#endif +} + +static int bitoffset; + +STATIC_INLINE void addbit (uae_u8 *p, int bit) +{ + int off1 = bitoffset / 8; + int off2 = bitoffset % 8; + p[off1] |= bit << (7 - off2); + bitoffset++; +} + + +struct pulse_sample { + uint32_t size; + int number_of_bits; +}; + + +#define FDI_MAX_ARRAY 10 /* change this value as you want */ +static int pulse_limitval = 15; /* tolerance of 15% */ +static struct pulse_sample psarray[FDI_MAX_ARRAY]; +static int array_index; +static unsigned long total; +static int totaldiv; + +static void init_array(uint32_t standard_MFM_2_bit_cell_size, int nb_of_bits) +{ + int i; + + for (i = 0; i < FDI_MAX_ARRAY; i++) { + psarray[i].size = standard_MFM_2_bit_cell_size; // That is (total track length / 50000) for Amiga double density + total += psarray[i].size; + psarray[i].number_of_bits = nb_of_bits; + totaldiv += psarray[i].number_of_bits; + } + array_index = 0; +} + +#if 0 + +static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *minp, uae_u32 *maxp, uae_u8 *idx, int maxidx, int *indexoffsetp, int pulses, int mfm) +{ + uint32_t adjust; + uint32_t adjusted_pulse; + uint32_t standard_MFM_2_bit_cell_size = totalavg / 50000; + uint32_t standard_MFM_8_bit_cell_size = totalavg / 12500; + int real_size, i, j, eodat, outstep; + int indexoffset = *indexoffsetp; + uae_u8 *d = fdi->track_dst_buffer; + uae_u16 *pt = fdi->track_dst_buffer_timing; + uae_u32 ref_pulse, pulse; + + /* detects a long-enough stable pulse coming just after another stable pulse */ + i = 1; + while ( (i < pulses) && ( (idx[i] < maxidx) + || (idx[i - 1] < maxidx) + || (avgp[i] < (standard_MFM_2_bit_cell_size - (standard_MFM_2_bit_cell_size / 4))) ) ) + i++; + if (i == pulses) { + outlog ("No stable and long-enough pulse in track.\n"); + return; + } + i--; + eodat = i; + adjust = 0; + total = 0; + totaldiv = 0; + init_array(standard_MFM_2_bit_cell_size, 2); + bitoffset = 0; + ref_pulse = 0; + outstep = 0; + while (outstep < 2) { + + /* calculates the current average bitrate from previous decoded data */ + uae_u32 avg_size = (total << 3) / totaldiv; /* this is the new average size for one MFM bit */ + /* uae_u32 avg_size = (uae_u32)((((float)total)*8.0) / ((float)totaldiv)); */ + /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */ + if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) || + (avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) { + //init_array(standard_MFM_2_bit_cell_size, 2); + avg_size = standard_MFM_8_bit_cell_size; + } + /* this is to prevent the average value from going too far + * from the theoretical value, otherwise it could progressively go to (2 * + * real value), or (real value / 2), etc. */ + + /* gets the next long-enough pulse (this may require more than one pulse) */ + pulse = 0; + while (pulse < ((avg_size / 4) - (avg_size / 16))) { + int indx; + i++; + if (i >= pulses) + i = 0; + indx = idx[i]; + if (rand() <= (indx * RAND_MAX) / maxidx) { + pulse += avgp[i] - ref_pulse; + if (indx >= maxidx) + ref_pulse = 0; + else + ref_pulse = avgp[i]; + } + if (i == eodat) + outstep++; + if (outstep == 1 && indexoffset == i) + *indexoffsetp = bitoffset; + } + + /* gets the size in bits from the pulse width, considering the current average bitrate */ + adjusted_pulse = pulse; + real_size = 0; + while (adjusted_pulse >= avg_size) { + real_size += 4; + adjusted_pulse -= avg_size / 2; + } + adjusted_pulse <<= 3; + while (adjusted_pulse >= ((avg_size * 4) + (avg_size / 4))) { + real_size += 2; + adjusted_pulse -= avg_size * 2; + } + if (adjusted_pulse >= ((avg_size * 3) + (avg_size / 4))) { + if (adjusted_pulse <= ((avg_size * 4) - (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) <= ((2 * avg_size) - (avg_size / 4))) + real_size += 3; + else + real_size += 4; + } else + real_size += 4; + } else { + if (adjusted_pulse > ((avg_size * 3) - (avg_size / 4))) { + real_size += 3; + } else { + if (adjusted_pulse >= ((avg_size * 2) + (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) < (avg_size + (avg_size / 4))) + real_size += 2; + else + real_size += 3; + } else + real_size += 2; + } + } + + if (outstep == 1) { + for (j = real_size; j > 1; j--) + addbit (d, 0); + addbit (d, 1); + for (j = 0; j < real_size; j++) + *pt++ = (uae_u16)(pulse / real_size); + } + + /* prepares for the next pulse */ + adjust = ((real_size * avg_size)/8) - pulse; + total -= psarray[array_index].size; + totaldiv -= psarray[array_index].number_of_bits; + psarray[array_index].size = pulse; + psarray[array_index].number_of_bits = real_size; + total += pulse; + totaldiv += real_size; + array_index++; + if (array_index >= FDI_MAX_ARRAY) + array_index = 0; + } + + fdi->out = bitoffset; +} + +#else + +static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *minp, uae_u32 *maxp, uae_u8 *idx, int maxidx, int *indexoffsetp, int pulses, int mfm) +{ + uint32_t adjust; + uint32_t adjusted_pulse; + uint32_t standard_MFM_2_bit_cell_size = totalavg / 50000; + uint32_t standard_MFM_8_bit_cell_size = totalavg / 12500; + int real_size, i, j, nexti, eodat, outstep, randval; + int indexoffset = *indexoffsetp; + uae_u8 *d = fdi->track_dst_buffer; + uae_u16 *pt = fdi->track_dst_buffer_timing; + uae_u32 ref_pulse, pulse; + long jitter; + + /* detects a long-enough stable pulse coming just after another stable pulse */ + i = 1; + while ( (i < pulses) && ( (idx[i] < maxidx) + || (idx[i - 1] < maxidx) + || (minp[i] < (standard_MFM_2_bit_cell_size - (standard_MFM_2_bit_cell_size / 4))) ) ) + i++; + if (i == pulses) { + outlog ("FDI: No stable and long-enough pulse in track.\n"); + return; + } + nexti = i; + eodat = i; + i--; + adjust = 0; + total = 0; + totaldiv = 0; + init_array(standard_MFM_2_bit_cell_size, 1 + mfm); + bitoffset = 0; + ref_pulse = 0; + jitter = 0; + outstep = -1; + while (outstep < 2) { + + /* calculates the current average bitrate from previous decoded data */ + uae_u32 avg_size = (total << (2 + mfm)) / totaldiv; /* this is the new average size for one MFM bit */ + /* uae_u32 avg_size = (uae_u32)((((float)total)*((float)(mfm+1))*4.0) / ((float)totaldiv)); */ + /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */ + if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) || + (avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) { + //init_array(standard_MFM_2_bit_cell_size, mfm + 1); + avg_size = standard_MFM_8_bit_cell_size; + } + /* this is to prevent the average value from going too far + * from the theoretical value, otherwise it could progressively go to (2 * + * real value), or (real value / 2), etc. */ + + /* gets the next long-enough pulse (this may require more than one pulse) */ + pulse = 0; + while (pulse < ((avg_size / 4) - (avg_size / 16))) { + uae_u32 avg_pulse, min_pulse, max_pulse; + i++; + if (i >= pulses) + i = 0; + if (i == nexti) { + do { + nexti++; + if (nexti >= pulses) + nexti = 0; + } while (idx[nexti] < maxidx); + } + if (idx[i] >= maxidx) { /* stable pulse */ + avg_pulse = avgp[i] - jitter; + min_pulse = minp[i]; + max_pulse = maxp[i]; + if (jitter >= 0) + max_pulse -= jitter; + else + min_pulse -= jitter; + if ((maxp[nexti] - avgp[nexti]) < (avg_pulse - min_pulse)) + min_pulse = avg_pulse - (maxp[nexti] - avgp[nexti]); + if ((avgp[nexti] - minp[nexti]) < (max_pulse - avg_pulse)) + max_pulse = avg_pulse + (avgp[nexti] - minp[nexti]); + if (min_pulse < ref_pulse) + min_pulse = ref_pulse; + randval = rand(); + if (randval < (RAND_MAX / 2)) { + if (randval > (RAND_MAX / 4)) { + if (randval <= (3 * RAND_MAX / 8)) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + jitter = 0 - (randval * (avg_pulse - min_pulse)) / RAND_MAX; + } else { + randval -= RAND_MAX / 2; + if (randval > (RAND_MAX / 4)) { + if (randval <= (3 * RAND_MAX / 8)) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + jitter = (randval * (max_pulse - avg_pulse)) / RAND_MAX; + } + avg_pulse += jitter; + if ((avg_pulse < min_pulse) || (avg_pulse > max_pulse)) { + outlog ("FDI: avg_pulse outside bounds! avg=%u min=%u max=%u\n", avg_pulse, min_pulse, max_pulse); + outlog ("FDI: avgp=%u (%u) minp=%u (%u) maxp=%u (%u) jitter=%d i=%d ni=%d\n", + avgp[i], avgp[nexti], minp[i], minp[nexti], maxp[i], maxp[nexti], jitter, i, nexti); + } + if (avg_pulse < ref_pulse) + outlog ("FDI: avg_pulse < ref_pulse! (%u < %u)\n", avg_pulse, ref_pulse); + pulse += avg_pulse - ref_pulse; + ref_pulse = 0; + if (i == eodat) + outstep++; + } else if (rand() <= ((idx[i] * RAND_MAX) / maxidx)) { + avg_pulse = avgp[i]; + min_pulse = minp[i]; + max_pulse = maxp[i]; + randval = rand(); + if (randval < (RAND_MAX / 2)) { + if (randval > (RAND_MAX / 4)) { + if (randval <= (3 * RAND_MAX / 8)) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + avg_pulse -= (randval * (avg_pulse - min_pulse)) / RAND_MAX; + } else { + randval -= RAND_MAX / 2; + if (randval > (RAND_MAX / 4)) { + if (randval <= (3 * RAND_MAX / 8)) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + avg_pulse += (randval * (max_pulse - avg_pulse)) / RAND_MAX; + } + if ((avg_pulse > ref_pulse) && (avg_pulse < (avgp[nexti] - jitter))) { + pulse += avg_pulse - ref_pulse; + ref_pulse = avg_pulse; + } + } + if (outstep == 1 && indexoffset == i) + *indexoffsetp = bitoffset; + } + + /* gets the size in bits from the pulse width, considering the current average bitrate */ + adjusted_pulse = pulse; + real_size = 0; + if (mfm) { + while (adjusted_pulse >= avg_size) { + real_size += 4; + adjusted_pulse -= avg_size / 2; + } + adjusted_pulse <<= 3; + while (adjusted_pulse >= ((avg_size * 4) + (avg_size / 4))) { + real_size += 2; + adjusted_pulse -= avg_size * 2; + } + if (adjusted_pulse >= ((avg_size * 3) + (avg_size / 4))) { + if (adjusted_pulse <= ((avg_size * 4) - (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) <= ((2 * avg_size) - (avg_size / 4))) + real_size += 3; + else + real_size += 4; + } else + real_size += 4; + } else { + if (adjusted_pulse > ((avg_size * 3) - (avg_size / 4))) { + real_size += 3; + } else { + if (adjusted_pulse >= ((avg_size * 2) + (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) < (avg_size + (avg_size / 4))) + real_size += 2; + else + real_size += 3; + } else + real_size += 2; + } + } + } else { + while (adjusted_pulse >= (2*avg_size)) + { + real_size+=4; + adjusted_pulse-=avg_size; + } + adjusted_pulse<<=2; + while (adjusted_pulse >= ((avg_size*3)+(avg_size/4))) + { + real_size+=2; + adjusted_pulse-=avg_size*2; + } + if (adjusted_pulse >= ((avg_size*2)+(avg_size/4))) + { + if (adjusted_pulse <= ((avg_size*3)-(avg_size/4))) + { + if (((adjusted_pulse>>1)-adjust) < (avg_size+(avg_size/4))) + real_size+=2; + else + real_size+=3; + } + else + real_size+=3; + } + else + { + if (adjusted_pulse > ((avg_size*2)-(avg_size/4))) + real_size+=2; + else + { + if (adjusted_pulse >= (avg_size+(avg_size/4))) + { + if (((adjusted_pulse>>1)-adjust) <= (avg_size-(avg_size/4))) + real_size++; + else + real_size+=2; + } + else + real_size++; + } + } + } + + /* after one pass to correctly initialize the average bitrate, outputs the bits */ + if (outstep == 1) { + for (j = real_size; j > 1; j--) + addbit (d, 0); + addbit (d, 1); + for (j = 0; j < real_size; j++) + *pt++ = (uae_u16)(pulse / real_size); + } + + /* prepares for the next pulse */ + adjust = ((real_size * avg_size) / (4 << mfm)) - pulse; + total -= psarray[array_index].size; + totaldiv -= psarray[array_index].number_of_bits; + psarray[array_index].size = pulse; + psarray[array_index].number_of_bits = real_size; + total += pulse; + totaldiv += real_size; + array_index++; + if (array_index >= FDI_MAX_ARRAY) + array_index = 0; + } + + fdi->out = bitoffset; +} + +#endif + +static void fdi2_celltiming (FDI *fdi, uint32_t totalavg, int bitoffset, uae_u16 *out) +{ + uae_u16 *pt2, *pt; + double avg_bit_len; + int i; + + avg_bit_len = (double)totalavg / (double)bitoffset; + pt2 = fdi->track_dst_buffer_timing; + pt = out; + for (i = 0; i < bitoffset / 8; i++) { + double v = (pt2[0] + pt2[1] + pt2[2] + pt2[3] + pt2[4] + pt2[5] + pt2[6] + pt2[7]) / 8.0; + v = 1000.0 * v / avg_bit_len; + *pt++ = (uae_u16)v; + pt2 += 8; + } + *pt++ = out[0]; + *pt = out[0]; +} + +static int decode_lowlevel_track (FDI *fdi, int track, struct fdi_cache *cache) +{ + uae_u8 *p1, *d; + uae_u32 *p2; + uae_u32 *avgp, *minp = 0, *maxp = 0; + uae_u8 *idxp = 0; + uae_u32 maxidx, totalavg, weakbits; + int i, j, len, pulses, indexoffset; + int avg_free, min_free = 0, max_free = 0, idx_free; + int idx_off1, idx_off2, idx_off3; + + d = fdi->track_dst; + p1 = fdi->track_src; + pulses = get_u32 (p1); + if (!pulses) + return -1; + p1 += 4; + len = 12; + avgp = (uae_u32*)fdi_decompress (pulses, p1 + 0, p1 + len, &avg_free); + dumpstream(track, (uae_u8*)avgp, pulses); + len += get_u24 (p1 + 0) & 0x3fffff; + if (!avgp) + return -1; + if (get_u24 (p1 + 3) && get_u24 (p1 + 6)) { + minp = (uae_u32*)fdi_decompress (pulses, p1 + 3, p1 + len, &min_free); + len += get_u24 (p1 + 3) & 0x3fffff; + maxp = (uae_u32*)fdi_decompress (pulses, p1 + 6, p1 + len, &max_free); + len += get_u24 (p1 + 6) & 0x3fffff; + /* Computes the real min and max values */ + for (i = 0; i < pulses; i++) { + maxp[i] = avgp[i] + minp[i] - maxp[i]; + minp[i] = avgp[i] - minp[i]; + } + } else { + minp = avgp; + maxp = avgp; + } + if (get_u24 (p1 + 9)) { + idx_off1 = 0; + idx_off2 = 1; + idx_off3 = 2; + idxp = fdi_decompress (pulses, p1 + 9, p1 + len, &idx_free); + if (idx_free) { + if (idxp[0] == 0 && idxp[1] == 0) { + idx_off1 = 2; + idx_off2 = 3; + } else { + idx_off1 = 1; + idx_off2 = 0; + } + idx_off3 = 4; + } + } else { + idxp = fdi_malloc (pulses * 2); + idx_free = 1; + for (i = 0; i < pulses; i++) { + idxp[i * 2 + 0] = 2; + idxp[i * 2 + 1] = 0; + } + idxp[0] = 1; + idxp[1] = 1; + } + + maxidx = 0; + indexoffset = 0; + p1 = idxp; + for (i = 0; i < pulses; i++) { + if (p1[idx_off1] + p1[idx_off2] > maxidx) + maxidx = p1[idx_off1] + p1[idx_off2]; + p1 += idx_off3; + } + p1 = idxp; + for (i = 0; (i < pulses) && (p1[idx_off2] != 0); i++) /* falling edge, replace with idx_off1 for rising edge */ + p1 += idx_off3; + if (i < pulses) { + j = i; + do { + i++; + p1 += idx_off3; + if (i >= pulses) { + i = 0; + p1 = idxp; + } + } while ((i != j) && (p1[idx_off2] == 0)); /* falling edge, replace with idx_off1 for rising edge */ + if (i != j) /* index pulse detected */ + { + while ((i != j) && (p1[idx_off1] > p1[idx_off2])) { /* falling edge, replace with "<" for rising edge */ + i++; + p1 += idx_off3; + if (i >= pulses) { + i = 0; + p1 = idxp; + } + } + if (i != j) + indexoffset = i; /* index position detected */ + } + } + p1 = idxp; + p2 = avgp; + totalavg = 0; + weakbits = 0; + for (i = 0; i < pulses; i++) { + int sum = p1[idx_off1] + p1[idx_off2]; + if (sum >= maxidx) { + totalavg += *p2; + } else { + weakbits++; + } + p2++; + p1 += idx_off3; + idxp[i] = sum; + } + len = totalavg / 100000; + outlog("totalavg=%u index=%d (%d) maxidx=%d weakbits=%d len=%d\n", + totalavg, indexoffset, maxidx, weakbits, len); + cache->avgp = avgp; + cache->idxp = idxp; + cache->minp = minp; + cache->maxp = maxp; + cache->avg_free = avg_free; + cache->idx_free = idx_free; + cache->min_free = min_free; + cache->max_free = max_free; + cache->totalavg = totalavg; + cache->pulses = pulses; + cache->maxidx = maxidx; + cache->indexoffset = indexoffset; + cache->weakbits = weakbits; + cache->lowlevel = 1; + + return 1; +} + +static unsigned char fdiid[]={"Formatted Disk Image file"}; +static int bit_rate_table[16] = { 125,150,250,300,500,1000 }; + +void fdi2raw_header_free (FDI *fdi) +{ + int i; + + fdi_free (fdi->mfmsync_buffer); + fdi_free (fdi->track_src_buffer); + fdi_free (fdi->track_dst_buffer); + fdi_free (fdi->track_dst_buffer_timing); + for (i = 0; i < MAX_TRACKS; i++) { + struct fdi_cache *c = &fdi->cache[i]; + if (c->idx_free) + fdi_free (c->idxp); + if (c->avg_free) + fdi_free (c->avgp); + if (c->min_free) + fdi_free (c->minp); + if (c->max_free) + fdi_free (c->maxp); + } + fdi_free (fdi); + debuglog ("FREE: memory allocated %d\n", fdi_allocated); +} + +int fdi2raw_get_last_track (FDI *fdi) +{ + return fdi->last_track; +} + +int fdi2raw_get_num_sector (FDI *fdi) +{ + if (fdi->header[152] == 0x02) + return 22; + return 11; +} + +int fdi2raw_get_last_head (FDI *fdi) +{ + return fdi->last_head; +} + +int fdi2raw_get_rotation (FDI *fdi) +{ + return fdi->rotation_speed; +} + +int fdi2raw_get_bit_rate (FDI *fdi) +{ + return fdi->bit_rate; +} + +int fdi2raw_get_type (FDI *fdi) +{ + return fdi->disk_type; +} + +int fdi2raw_get_write_protect (FDI *fdi) +{ + return fdi->write_protect; +} + +FDI *fdi2raw_header(FILE *f) +{ + int i, offset, oldseek; + uae_u8 type, size; + FDI *fdi; + + debuglog ("ALLOC: memory allocated %d\n", fdi_allocated); + fdi = fdi_malloc(sizeof(FDI)); + memset (fdi, 0, sizeof (FDI)); + fdi->file = f; + oldseek = ftell (fdi->file); + fseek (fdi->file, 0, SEEK_SET); + fread (fdi->header, 2048, 1, fdi->file); + fseek (fdi->file, oldseek, SEEK_SET); + if (memcmp (fdiid, fdi->header, strlen ((char *)fdiid)) ) { + fdi_free(fdi); + return NULL; + } + if ((fdi->header[140] != 1 && fdi->header[140] != 2) || (fdi->header[141] != 0 && !(fdi->header[140]==2 && fdi->header[141]==1))) { + fdi_free(fdi); + return NULL; + } + + fdi->mfmsync_buffer = fdi_malloc (MAX_MFM_SYNC_BUFFER * sizeof(int)); + fdi->track_src_buffer = fdi_malloc (MAX_SRC_BUFFER); + fdi->track_dst_buffer = fdi_malloc (MAX_DST_BUFFER); + fdi->track_dst_buffer_timing = fdi_malloc (MAX_TIMING_BUFFER); + + fdi->last_track = ((fdi->header[142] << 8) + fdi->header[143]) + 1; + fdi->last_track *= fdi->header[144] + 1; + if (fdi->last_track > MAX_TRACKS) + fdi->last_track = MAX_TRACKS; + fdi->last_head = fdi->header[144]; + fdi->disk_type = fdi->header[145]; + fdi->rotation_speed = fdi->header[146] + 128; + fdi->write_protect = fdi->header[147] & 1; + outlog ("FDI version %d.%d\n", fdi->header[140], fdi->header[141]); + outlog ("last_track=%d rotation_speed=%d\n",fdi->last_track,fdi->rotation_speed); + + offset = 512; + i = fdi->last_track; + if (i > 180) { + offset += 512; + i -= 180; + while (i > 256) { + offset += 512; + i -= 256; + } + } + for (i = 0; i < fdi->last_track; i++) { + fdi->track_offsets[i] = offset; + type = fdi->header[152 + i * 2]; + size = fdi->header[152 + i * 2 + 1]; + if (type == 1) + offset += (size & 15) * 512; + else if ((type & 0xc0) == 0x80) + offset += (((type & 0x3f) << 8) | size) * 256; + else + offset += size * 256; + } + fdi->track_offsets[i] = offset; + + return fdi; +} + + +int fdi2raw_loadrevolution_2 (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int *indexoffsetp, int *multirev, int mfm) +{ + struct fdi_cache *cache = &fdi->cache[track]; + int len, i, idx; + + memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER); + idx = cache->indexoffset; + fdi2_decode (fdi, cache->totalavg, + cache->avgp, cache->minp, cache->maxp, cache->idxp, + cache->maxidx, &idx, cache->pulses, mfm); + //fdi2_gcr_decode (fdi, totalavg, avgp, minp, maxp, idxp, idx_off1, idx_off2, idx_off3, maxidx, pulses); + outlog("track %d: nbits=%d avg len=%.2f weakbits=%d idx=%d\n", + track, bitoffset, (double)cache->totalavg / bitoffset, cache->weakbits, cache->indexoffset); + len = fdi->out; + if (cache->weakbits >= 10 && multirev) + *multirev = 1; + *tracklength = len; + + for (i = 0; i < (len + 15) / (2 * 8); i++) { + uae_u8 *data = fdi->track_dst_buffer + i * 2; + *mfmbuf++ = 256 * *data + *(data + 1); + } + fdi2_celltiming (fdi, cache->totalavg, len, tracktiming); + if (indexoffsetp) + *indexoffsetp = idx; + return 1; +} + +int fdi2raw_loadrevolution (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int mfm) +{ + return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, 0, 0, mfm); +} + +int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int *indexoffsetp, int *multirev, int mfm) +{ + uae_u8 *p; + int outlen, i; + struct fdi_cache *cache = &fdi->cache[track]; + + if (cache->lowlevel) + return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, indexoffsetp, multirev, mfm); + + fdi->err = 0; + fdi->track_src_len = fdi->track_offsets[track + 1] - fdi->track_offsets[track]; + fseek (fdi->file, fdi->track_offsets[track], SEEK_SET); + fread (fdi->track_src_buffer, fdi->track_src_len, 1, fdi->file); + memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER); + fdi->track_dst_buffer_timing[0] = 0; + + fdi->current_track = track; + fdi->track_src = fdi->track_src_buffer; + fdi->track_dst = fdi->track_dst_buffer; + p = fdi->header + 152 + fdi->current_track * 2; + fdi->track_type = *p++; + fdi->track_len = *p++; + fdi->bit_rate = 0; + fdi->out = 0; + fdi->mfmsync_offset = 0; + + if ((fdi->track_type & 0xf0) == 0xf0 || (fdi->track_type & 0xf0) == 0xe0) + fdi->bit_rate = bit_rate_table[fdi->track_type & 0x0f]; + else + fdi->bit_rate = 250; + + outlog ("track %d: srclen: %d track_type: %02.2X, bitrate: %d\n", + fdi->current_track, fdi->track_src_len, fdi->track_type, fdi->bit_rate); + + if ((fdi->track_type & 0xc0) == 0x80) { + + outlen = decode_lowlevel_track (fdi, track, cache); + + } else if ((fdi->track_type & 0xf0) == 0xf0) { + + outlen = decode_raw_track (fdi); + + } else if ((fdi->track_type & 0xf0) == 0xe0) { + + outlen = handle_sectors_described_track (fdi); + + } else if ((fdi->track_type & 0xf0)) { + + zxx (fdi); + outlen = -1; + + } else if (fdi->track_type < 0x10) { + + decode_normal_track[fdi->track_type](fdi); + fix_mfm_sync (fdi); + outlen = fdi->out; + + } else { + + zxx (fdi); + outlen = -1; + + } + +// amiga_check_track (fdi); + + if (fdi->err) + return 0; + + if (outlen > 0) { + if (cache->lowlevel) + return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, indexoffsetp, multirev, mfm); + *tracklength = fdi->out; + for (i = 0; i < ((*tracklength) + 15) / (2 * 8); i++) { + uae_u8 *data = fdi->track_dst_buffer + i * 2; + *mfmbuf++ = 256 * *data + *(data + 1); + } + } + return outlen; +} + diff --git a/src/fdi2raw.h b/src/fdi2raw.h new file mode 100644 index 000000000..92e6ab1a3 --- /dev/null +++ b/src/fdi2raw.h @@ -0,0 +1,34 @@ +#ifndef __FDI2RAW_H +#define __FDI2RAW_H + +#define uae_u8 uint8_t +#define uae_u16 uint16_t +#define uae_u32 uint32_t + +//#include "types.h" +#include +typedef struct fdi FDI; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int fdi2raw_loadtrack (FDI*, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int *indexoffset, int *multirev, int mfm); + +extern int fdi2raw_loadrevolution (FDI*, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int mfm); + +extern FDI *fdi2raw_header(FILE *f); +extern void fdi2raw_header_free (FDI *); +extern int fdi2raw_get_last_track(FDI *); +extern int fdi2raw_get_num_sector (FDI *); +extern int fdi2raw_get_last_head(FDI *); +extern int fdi2raw_get_type (FDI *); +extern int fdi2raw_get_bit_rate (FDI *); +extern int fdi2raw_get_rotation (FDI *); +extern int fdi2raw_get_write_protect (FDI *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/filters.h b/src/filters.h new file mode 100644 index 000000000..8119101e1 --- /dev/null +++ b/src/filters.h @@ -0,0 +1,281 @@ +#define NCoef 2 + +//fc=350Hz +static inline float low_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.00049713569693400649, + 0.00099427139386801299, + 0.00049713569693400649 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955470669530000, + 0.93726236021404663000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=350Hz +static inline float low_cut_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.96839970114733542000, + -1.93679940229467080000, + 0.96839970114733542000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955471202770000, + 0.93726236021916731000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=3.5kHz +static inline float high_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.72248704753064896000, + -1.44497409506129790000, + 0.72248704753064896000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781670578510000, + 0.52352474706139873000 + }; + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=3.5kHz +static inline float high_cut_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.03927726802250377400, + 0.07855453604500754700, + 0.03927726802250377400 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781666419950000, + 0.52352474703279628000 + }; + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + + +#undef NCoef +#define NCoef 1 + +//fc=3.2kHz +static inline float sb_iir(int i, float NewSample) { +/* float ACoef[NCoef+1] = { + 0.03356837051492005100, + 0.06713674102984010200, + 0.03356837051492005100 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.41898265221812010000, + 0.55326988968868285000 + };*/ + + float ACoef[NCoef+1] = { + 0.17529642630084405000, + 0.17529642630084405000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -0.64940759319751051000 + }; + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + + + +#undef NCoef +#define NCoef 2 + +//fc=150Hz +static inline float adgold_highpass_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.98657437157334349000, + -1.97314874314668700000, + 0.98657437157334349000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.97223372919758360000, + 0.97261396931534050000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=150Hz +static inline float adgold_lowpass_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.00009159473951071446, + 0.00018318947902142891, + 0.00009159473951071446 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.97223372919526560000, + 0.97261396931306277000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=56Hz +static inline float adgold_pseudo_stereo_iir(float NewSample) { + float ACoef[NCoef+1] = { + 0.00001409030866231767, + 0.00002818061732463533, + 0.00001409030866231767 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.98733021473466760000, + 0.98738361004063568000 + }; + + static float y[NCoef+1]; //output samples + static float x[NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[n] = x[n-1]; + y[n] = y[n-1]; + } + + //Calculate the new output + x[0] = NewSample; + y[0] = ACoef[0] * x[0]; + for(n=1; n<=NCoef; n++) + y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; + + return y[0]; +} diff --git a/src/gameport.c b/src/gameport.c new file mode 100644 index 000000000..3724d8e91 --- /dev/null +++ b/src/gameport.c @@ -0,0 +1,223 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "plat-joystick.h" +#include "timer.h" + +#include "gameport.h" +#include "joystick_standard.h" +#include "joystick_sw_pad.h" + +int joystick_type; + +static joystick_if_t *joystick_list[] = +{ + &joystick_standard, + &joystick_standard_4button, + &joystick_standard_6button, + &joystick_standard_8button, + &joystick_sw_pad, + NULL +}; + +char *joystick_get_name(int joystick) +{ + if (!joystick_list[joystick]) + return NULL; + return joystick_list[joystick]->name; +} + +int joystick_get_max_joysticks(int joystick) +{ + return joystick_list[joystick]->max_joysticks; +} + +int joystick_get_axis_count(int joystick) +{ + return joystick_list[joystick]->axis_count; +} + +int joystick_get_button_count(int joystick) +{ + return joystick_list[joystick]->button_count; +} + +char *joystick_get_axis_name(int joystick, int id) +{ + return joystick_list[joystick]->axis_names[id]; +} + +char *joystick_get_button_name(int joystick, int id) +{ + return joystick_list[joystick]->button_names[id]; +} + +typedef struct gameport_axis_t +{ + int count; + int axis_nr; + struct gameport_t *gameport; +} gameport_axis_t; + +typedef struct gameport_t +{ + uint8_t state; + + gameport_axis_t axis[4]; + + joystick_if_t *joystick; + void *joystick_dat; +} gameport_t; + +static gameport_t *gameport_global = NULL; + +static int gameport_time(int axis) +{ + if (axis == AXIS_NOT_PRESENT) + return 0; + + axis += 32768; + axis = (axis * 100) / 65; /*Axis now in ohms*/ + axis = (axis * 11) / 1000; + return TIMER_USEC * (axis + 24); /*max = 11.115 ms*/ +} + +void gameport_write(uint16_t addr, uint8_t val, void *p) +{ + gameport_t *gameport = (gameport_t *)p; + + timer_clock(); + gameport->state |= 0x0f; +// pclog("gameport_write : joysticks_present=%i\n", joysticks_present); + + gameport->axis[0].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 0)); + gameport->axis[1].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 1)); + gameport->axis[2].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 2)); + gameport->axis[3].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 3)); + + gameport->joystick->write(gameport->joystick_dat); + + cycles -= ISA_CYCLES(8); +} + +uint8_t gameport_read(uint16_t addr, void *p) +{ + gameport_t *gameport = (gameport_t *)p; + uint8_t ret; + + timer_clock(); +// if (joysticks_present) + ret = gameport->state | gameport->joystick->read(gameport->joystick_dat);//0xf0; +// else +// ret = 0xff; + +// pclog("gameport_read: ret=%02x %08x:%08x isa_cycles=%i %i\n", ret, cs, cpu_state.pc, isa_cycles, gameport->axis[0].count); + + cycles -= ISA_CYCLES(8); + + return ret; +} + +void gameport_timer_over(void *p) +{ + gameport_axis_t *axis = (gameport_axis_t *)p; + gameport_t *gameport = axis->gameport; + + gameport->state &= ~(1 << axis->axis_nr); + axis->count = 0; + + if (axis == &gameport->axis[0]) + gameport->joystick->a0_over(gameport->joystick_dat); +} + +void *gameport_init_common() +{ + gameport_t *gameport = malloc(sizeof(gameport_t)); + + memset(gameport, 0, sizeof(gameport_t)); + + gameport->axis[0].gameport = gameport; + gameport->axis[1].gameport = gameport; + gameport->axis[2].gameport = gameport; + gameport->axis[3].gameport = gameport; + + gameport->axis[0].axis_nr = 0; + gameport->axis[1].axis_nr = 1; + gameport->axis[2].axis_nr = 2; + gameport->axis[3].axis_nr = 3; + + timer_add(gameport_timer_over, &gameport->axis[0].count, &gameport->axis[0].count, &gameport->axis[0]); + timer_add(gameport_timer_over, &gameport->axis[1].count, &gameport->axis[1].count, &gameport->axis[1]); + timer_add(gameport_timer_over, &gameport->axis[2].count, &gameport->axis[2].count, &gameport->axis[2]); + timer_add(gameport_timer_over, &gameport->axis[3].count, &gameport->axis[3].count, &gameport->axis[3]); + + gameport->joystick = joystick_list[joystick_type]; + gameport->joystick_dat = gameport->joystick->init(); + + gameport_global = gameport; + + return gameport; +} + +void gameport_update_joystick_type() +{ + gameport_t *gameport = gameport_global; + + gameport->joystick->close(gameport->joystick_dat); + gameport->joystick = joystick_list[joystick_type]; + gameport->joystick_dat = gameport->joystick->init(); +} + +void *gameport_init() +{ + gameport_t *gameport = gameport_init_common(); + + io_sethandler(0x0200, 0x0008, gameport_read, NULL, NULL, gameport_write, NULL, NULL, gameport); + + return gameport; +} + +void *gameport_201_init() +{ + gameport_t *gameport = gameport_init_common(); + + io_sethandler(0x0201, 0x0001, gameport_read, NULL, NULL, gameport_write, NULL, NULL, gameport); + + return gameport; +} + +void gameport_close(void *p) +{ + gameport_t *gameport = (gameport_t *)p; + + gameport->joystick->close(gameport->joystick_dat); + + gameport_global = NULL; + + free(gameport); +} + +device_t gameport_device = +{ + "Game port", + 0, + gameport_init, + gameport_close, + NULL, + NULL, + NULL, + NULL +}; + +device_t gameport_201_device = +{ + "Game port (port 201h only)", + 0, + gameport_201_init, + gameport_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/gameport.h b/src/gameport.h new file mode 100644 index 000000000..cca311e25 --- /dev/null +++ b/src/gameport.h @@ -0,0 +1,29 @@ +extern device_t gameport_device; +extern device_t gameport_201_device; + +typedef struct +{ + char name[80]; + void *(*init)(); + void (*close)(void *p); + uint8_t (*read)(void *p); + void (*write)(void *p); + int (*read_axis)(void *p, int axis); + void (*a0_over)(void *p); + int axis_count, button_count; + int max_joysticks; + char axis_names[8][32]; + char button_names[32][32]; +} joystick_if_t; + +extern int joystick_type; +char *joystick_get_name(int joystick); +int joystick_get_max_joysticks(int joystick); +int joystick_get_axis_count(int joystick); +int joystick_get_button_count(int joystick); +char *joystick_get_axis_name(int joystick, int id); +char *joystick_get_button_name(int joystick, int id); + +void gameport_update_joystick_type(); + +#define AXIS_NOT_PRESENT -99999 diff --git a/src/headland.c b/src/headland.c new file mode 100644 index 000000000..834c6947d --- /dev/null +++ b/src/headland.c @@ -0,0 +1,46 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "cpu.h" + +#include "headland.h" + +static int headland_index; +static uint8_t headland_regs[256]; + +void headland_write(uint16_t addr, uint8_t val, void *priv) +{ + if (addr & 1) + { + if (headland_index == 0xc1 && !is486) val = 0; + headland_regs[headland_index] = val; + pclog("Headland write %02X %02X\n",headland_index,val); + if (headland_index == 0x82) + { + shadowbios = val & 0x10; + shadowbios_write = !(val & 0x10); + if (shadowbios) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } + } + else + headland_index = val; +} + +uint8_t headland_read(uint16_t addr, void *priv) +{ + if (addr & 1) + { + if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return headland_regs[headland_index]; + } + return headland_index; +} + +void headland_init() +{ + io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); +} diff --git a/src/headland.h b/src/headland.h new file mode 100644 index 000000000..f9334fd6f --- /dev/null +++ b/src/headland.h @@ -0,0 +1 @@ +void headland_init(); diff --git a/src/i430fx.c b/src/i430fx.c new file mode 100644 index 000000000..524b3a0db --- /dev/null +++ b/src/i430fx.c @@ -0,0 +1,161 @@ +#include + +#include "ibm.h" +#include "mem.h" +#include "pci.h" + +#include "i430fx.h" + +static uint8_t card_i430fx[256]; + +static void i430fx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430fx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430fx[0x59] ^ val) & 0xf0) + { + i430fx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + pclog("i430fx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430fx[0x5a] ^ val) & 0x0f) + i430fx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430fx[0x5a] ^ val) & 0xf0) + i430fx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i430fx[0x5b] ^ val) & 0x0f) + i430fx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430fx[0x5b] ^ val) & 0xf0) + i430fx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i430fx[0x5c] ^ val) & 0x0f) + i430fx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430fx[0x5c] ^ val) & 0xf0) + i430fx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430fx[0x5d] ^ val) & 0x0f) + i430fx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430fx[0x5d] ^ val) & 0xf0) + i430fx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430fx[0x5e] ^ val) & 0x0f) + i430fx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430fx[0x5e] ^ val) & 0xf0) + i430fx_map(0xe4000, 0x04000, val >> 4); + pclog("i430fx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430fx[0x5f] ^ val) & 0x0f) + i430fx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430fx[0x5f] ^ val) & 0xf0) + i430fx_map(0xec000, 0x04000, val >> 4); + pclog("i430fx_write : PAM6 write %02X\n", val); + break; + } + + card_i430fx[addr] = val; +} + +uint8_t i430fx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430fx[addr]; +} + +/*The Turbo-Reset Control Register isn't listed in the i430FX datasheet, however + the Advanced/EV BIOS seems to assume it exists. It aliases with one of the PCI + registers.*/ +static uint8_t trc = 0; + +void i430fx_trc_write(uint16_t port, uint8_t val, void *p) +{ + if ((val & 4) && !(trc & 4)) + { + if (val & 2) /*Hard reset*/ + i430fx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ + resetx86(); + } + + trc = val; +} + +void i430fx_init() +{ + pci_add_specific(0, i430fx_read, i430fx_write, NULL); + + memset(card_i430fx, 0, 256); + card_i430fx[0x00] = 0x86; card_i430fx[0x01] = 0x80; /*Intel*/ + card_i430fx[0x02] = 0x22; card_i430fx[0x03] = 0x01; /*SB82437FX-66*/ + card_i430fx[0x04] = 0x06; card_i430fx[0x05] = 0x00; + card_i430fx[0x06] = 0x00; card_i430fx[0x07] = 0x82; + if (romset == ROM_MB500N) card_i430fx[0x07] = 0x02; + card_i430fx[0x08] = 0x00; /*A0 stepping*/ + card_i430fx[0x09] = 0x00; card_i430fx[0x0a] = 0x00; card_i430fx[0x0b] = 0x06; + card_i430fx[0x52] = 0x40; /*256kb PLB cache*/ + if (romset == ROM_MB500N) + { + card_i430fx[0x52] = 0x42; + card_i430fx[0x53] = 0x14; + card_i430fx[0x56] = 0x52; /*DRAM control*/ + } +// card_i430fx[0x53] = 0x14; +// card_i430fx[0x56] = 0x52; /*DRAM control*/ + card_i430fx[0x57] = 0x01; + card_i430fx[0x60] = card_i430fx[0x61] = card_i430fx[0x62] = card_i430fx[0x63] = card_i430fx[0x64] = 0x02; + if (romset == ROM_MB500N) + { + card_i430fx[0x67] = 0x11; + card_i430fx[0x69] = 0x03; + card_i430fx[0x70] = 0x20; + } +// card_i430fx[0x67] = 0x11; +// card_i430fx[0x69] = 0x03; +// card_i430fx[0x70] = 0x20; + card_i430fx[0x72] = 0x02; +// card_i430fx[0x74] = 0x0e; +// card_i430fx[0x78] = 0x23; + if (romset == ROM_MB500N) + { + card_i430fx[0x74] = 0x0e; + card_i430fx[0x78] = 0x23; + } + + if (romset != ROM_MB500N) io_sethandler(0x0cf9, 0x0001, NULL, NULL, NULL, i430fx_trc_write, NULL, NULL, NULL); +} diff --git a/src/i430fx.h b/src/i430fx.h new file mode 100644 index 000000000..98b901ab9 --- /dev/null +++ b/src/i430fx.h @@ -0,0 +1 @@ +void i430fx_init(); diff --git a/src/i430hx.c b/src/i430hx.c new file mode 100644 index 000000000..71ec621e1 --- /dev/null +++ b/src/i430hx.c @@ -0,0 +1,128 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "i430hx.h" + +static uint8_t card_i430hx[256]; + +static void i430hx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430hx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430hx[0x59] ^ val) & 0xf0) + { + i430hx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + // pclog("i430hx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430hx[0x5a] ^ val) & 0x0f) + i430hx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430hx[0x5a] ^ val) & 0xf0) + i430hx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i430hx[0x5b] ^ val) & 0x0f) + i430hx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430hx[0x5b] ^ val) & 0xf0) + i430hx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i430hx[0x5c] ^ val) & 0x0f) + i430hx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430hx[0x5c] ^ val) & 0xf0) + i430hx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430hx[0x5d] ^ val) & 0x0f) + i430hx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430hx[0x5d] ^ val) & 0xf0) + i430hx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430hx[0x5e] ^ val) & 0x0f) + i430hx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430hx[0x5e] ^ val) & 0xf0) + i430hx_map(0xe4000, 0x04000, val >> 4); + // pclog("i430hx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430hx[0x5f] ^ val) & 0x0f) + i430hx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430hx[0x5f] ^ val) & 0xf0) + i430hx_map(0xec000, 0x04000, val >> 4); + // pclog("i430hx_write : PAM6 write %02X\n", val); + break; + } + + card_i430hx[addr] = val; +} + +uint8_t i430hx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430hx[addr]; +} + + +void i430hx_init() +{ + pci_add_specific(0, i430hx_read, i430hx_write, NULL); + + memset(card_i430hx, 0, 256); + card_i430hx[0x00] = 0x86; card_i430hx[0x01] = 0x80; /*Intel*/ + card_i430hx[0x02] = 0x50; card_i430hx[0x03] = 0x12; /*82439HX*/ + card_i430hx[0x04] = 0x06; card_i430hx[0x05] = 0x00; + card_i430hx[0x06] = 0x00; card_i430hx[0x07] = 0x02; + card_i430hx[0x08] = 0x00; /*A0 stepping*/ + card_i430hx[0x09] = 0x00; card_i430hx[0x0a] = 0x00; card_i430hx[0x0b] = 0x06; + // card_i430hx[0x52] = 0x42; /*256kb PLB cache*/ + card_i430hx[0x51] = 0x20; + // card_i430hx[0x52] = 0xB2; /*512kb cache*/ + card_i430hx[0x52] = 0xB5; /*512kb cache*/ + + card_i430hx[0x59] = 0x40; + card_i430hx[0x5A] = card_i430hx[0x5B] = card_i430hx[0x5C] = card_i430hx[0x5D] = card_i430hx[0x5E] = card_i430hx[0x5F] = 0x44; + + card_i430hx[0x56] = 0x52; /*DRAM control*/ + card_i430hx[0x57] = 0x01; + card_i430hx[0x60] = card_i430hx[0x61] = card_i430hx[0x62] = card_i430hx[0x63] = card_i430hx[0x64] = card_i430hx[0x65] = card_i430hx[0x66] = card_i430hx[0x67] = 0x02; + card_i430hx[0x68] = 0x11; + card_i430hx[0x72] = 0x02; +} diff --git a/src/i430hx.h b/src/i430hx.h new file mode 100644 index 000000000..b9a6b22e6 --- /dev/null +++ b/src/i430hx.h @@ -0,0 +1 @@ +void i430hx_init(); diff --git a/src/i430lx.c b/src/i430lx.c new file mode 100644 index 000000000..8738b7bd0 --- /dev/null +++ b/src/i430lx.c @@ -0,0 +1,149 @@ +#include + +#include "ibm.h" +#include "mem.h" +#include "pci.h" + +#include "i430lx.h" + +static uint8_t card_i430lx[256]; + +static void i430lx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430lx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430lx[0x59] ^ val) & 0xf0) + { + i430lx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + pclog("i430lx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430lx[0x5a] ^ val) & 0x0f) + i430lx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430lx[0x5a] ^ val) & 0xf0) + i430lx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if (romset == ROM_REVENGE) + { + if ((card_i430lx[0x5b] ^ val) & 0x0f) + i430lx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430lx[0x5b] ^ val) & 0xf0) + i430lx_map(0xcc000, 0x04000, val >> 4); + } + break; + case 0x5c: /*PAM3*/ + if ((card_i430lx[0x5c] ^ val) & 0x0f) + i430lx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430lx[0x5c] ^ val) & 0xf0) + i430lx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430lx[0x5d] ^ val) & 0x0f) + i430lx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430lx[0x5d] ^ val) & 0xf0) + i430lx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430lx[0x5e] ^ val) & 0x0f) + i430lx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430lx[0x5e] ^ val) & 0xf0) + i430lx_map(0xe4000, 0x04000, val >> 4); + pclog("i430lx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430lx[0x5f] ^ val) & 0x0f) + i430lx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430lx[0x5f] ^ val) & 0xf0) + i430lx_map(0xec000, 0x04000, val >> 4); + pclog("i430lx_write : PAM6 write %02X\n", val); + break; + } + + card_i430lx[addr] = val; +} + +uint8_t i430lx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430lx[addr]; +} + +static uint8_t trc = 0; + +uint8_t i430lx_trc_read(uint16_t port, void *p) +{ + return trc; +} + +void i430lx_trc_write(uint16_t port, uint8_t val, void *p) +{ + if ((val & 4) && !(trc & 4)) + { + if (val & 2) /*Hard reset*/ + i430lx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ + resetx86(); + } + + trc = val; +} + +void i430lx_init() +{ + pci_add_specific(0, i430lx_read, i430lx_write, NULL); + + memset(card_i430lx, 0, 256); + card_i430lx[0x00] = 0x86; card_i430lx[0x01] = 0x80; /*Intel*/ + card_i430lx[0x02] = 0xa3; card_i430lx[0x03] = 0x04; /*82434LX*/ + card_i430lx[0x04] = 0x06; card_i430lx[0x05] = 0x00; + card_i430lx[0x06] = 0x00; card_i430lx[0x07] = 0x02; + card_i430lx[0x08] = 0x03; /*A3 stepping*/ + card_i430lx[0x09] = 0x00; card_i430lx[0x0a] = 0x00; card_i430lx[0x0b] = 0x06; + card_i430lx[0x50] = 0x80; + card_i430lx[0x52] = 0x40; /*256kb PLB cache*/ +// card_i430lx[0x53] = 0x14; +// card_i430lx[0x56] = 0x52; /*DRAM control*/ + card_i430lx[0x57] = 0x31; + card_i430lx[0x60] = card_i430lx[0x61] = card_i430lx[0x62] = card_i430lx[0x63] = card_i430lx[0x64] = 0x02; +// card_i430lx[0x67] = 0x11; +// card_i430lx[0x69] = 0x03; +// card_i430lx[0x70] = 0x20; +// card_i430lx[0x72] = 0x02; +// card_i430lx[0x74] = 0x0e; +// card_i430lx[0x78] = 0x23; + + io_sethandler(0x0cf9, 0x0001, i430lx_trc_read, NULL, NULL, i430lx_trc_write, NULL, NULL, NULL); +} diff --git a/src/i430lx.h b/src/i430lx.h new file mode 100644 index 000000000..84d1e0ebf --- /dev/null +++ b/src/i430lx.h @@ -0,0 +1 @@ +void i430lx_init(); diff --git a/src/i430nx.c b/src/i430nx.c new file mode 100644 index 000000000..60eb79b62 --- /dev/null +++ b/src/i430nx.c @@ -0,0 +1,147 @@ +#include + +#include "ibm.h" +#include "mem.h" +#include "pci.h" + +#include "i430nx.h" + +static uint8_t card_i430nx[256]; + +static void i430nx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430nx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430nx[0x59] ^ val) & 0xf0) + { + i430nx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + pclog("i430nx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430nx[0x5a] ^ val) & 0x0f) + i430nx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430nx[0x5a] ^ val) & 0xf0) + i430nx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i430nx[0x5b] ^ val) & 0x0f) + i430nx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430nx[0x5b] ^ val) & 0xf0) + i430nx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i430nx[0x5c] ^ val) & 0x0f) + i430nx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430nx[0x5c] ^ val) & 0xf0) + i430nx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430nx[0x5d] ^ val) & 0x0f) + i430nx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430nx[0x5d] ^ val) & 0xf0) + i430nx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430nx[0x5e] ^ val) & 0x0f) + i430nx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430nx[0x5e] ^ val) & 0xf0) + i430nx_map(0xe4000, 0x04000, val >> 4); + pclog("i430nx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430nx[0x5f] ^ val) & 0x0f) + i430nx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430nx[0x5f] ^ val) & 0xf0) + i430nx_map(0xec000, 0x04000, val >> 4); + pclog("i430nx_write : PAM6 write %02X\n", val); + break; + } + + card_i430nx[addr] = val; +} + +uint8_t i430nx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430nx[addr]; +} + +static uint8_t trc = 0; + +uint8_t i430nx_trc_read(uint16_t port, void *p) +{ + return trc; +} + +void i430nx_trc_write(uint16_t port, uint8_t val, void *p) +{ + if ((val & 4) && !(trc & 4)) + { + if (val & 2) /*Hard reset*/ + i430nx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ + resetx86(); + } + + trc = val; +} + +void i430nx_init() +{ + pci_add_specific(0, i430nx_read, i430nx_write, NULL); + + memset(card_i430nx, 0, 256); + card_i430nx[0x00] = 0x86; card_i430nx[0x01] = 0x80; /*Intel*/ + card_i430nx[0x02] = 0xa3; card_i430nx[0x03] = 0x04; /*82434NX*/ + card_i430nx[0x04] = 0x06; card_i430nx[0x05] = 0x00; + card_i430nx[0x06] = 0x00; card_i430nx[0x07] = 0x02; + card_i430nx[0x08] = 0x10; /*A0 stepping*/ + card_i430nx[0x09] = 0x00; card_i430nx[0x0a] = 0x00; card_i430nx[0x0b] = 0x06; + card_i430nx[0x50] = 0xA0; + card_i430nx[0x52] = 0x44; /*256kb PLB cache*/ +// card_i430nx[0x53] = 0x14; +// card_i430nx[0x56] = 0x52; /*DRAM control*/ + card_i430nx[0x57] = 0x31; + card_i430nx[0x60] = card_i430nx[0x61] = card_i430nx[0x62] = card_i430nx[0x63] = card_i430nx[0x64] = 0x02; + card_i430nx[0x66] = card_i430nx[0x67] = 0x02; +// card_i430nx[0x67] = 0x11; +// card_i430nx[0x69] = 0x03; +// card_i430nx[0x70] = 0x20; +// card_i430nx[0x72] = 0x02; +// card_i430nx[0x74] = 0x0e; +// card_i430nx[0x78] = 0x23; + + io_sethandler(0x0cf9, 0x0001, i430nx_trc_read, NULL, NULL, i430nx_trc_write, NULL, NULL, NULL); +} diff --git a/src/i430nx.h b/src/i430nx.h new file mode 100644 index 000000000..dfc5bd495 --- /dev/null +++ b/src/i430nx.h @@ -0,0 +1 @@ +void i430nx_init(); diff --git a/src/i430vx.c b/src/i430vx.c new file mode 100644 index 000000000..f324687c5 --- /dev/null +++ b/src/i430vx.c @@ -0,0 +1,126 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "i430vx.h" + +static uint8_t card_i430vx[256]; + +static void i430vx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430vx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430vx[0x59] ^ val) & 0xf0) + { + i430vx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + pclog("i430vx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430vx[0x5a] ^ val) & 0x0f) + i430vx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430vx[0x5a] ^ val) & 0xf0) + i430vx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i430vx[0x5b] ^ val) & 0x0f) + i430vx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430vx[0x5b] ^ val) & 0xf0) + i430vx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i430vx[0x5c] ^ val) & 0x0f) + i430vx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430vx[0x5c] ^ val) & 0xf0) + i430vx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430vx[0x5d] ^ val) & 0x0f) + i430vx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430vx[0x5d] ^ val) & 0xf0) + i430vx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430vx[0x5e] ^ val) & 0x0f) + i430vx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430vx[0x5e] ^ val) & 0xf0) + i430vx_map(0xe4000, 0x04000, val >> 4); + pclog("i430vx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430vx[0x5f] ^ val) & 0x0f) + i430vx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430vx[0x5f] ^ val) & 0xf0) + i430vx_map(0xec000, 0x04000, val >> 4); + pclog("i430vx_write : PAM6 write %02X\n", val); + break; + } + + card_i430vx[addr] = val; +} + +uint8_t i430vx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430vx[addr]; +} + + +void i430vx_init() +{ + pci_add_specific(0, i430vx_read, i430vx_write, NULL); + + memset(card_i430vx, 0, 256); + card_i430vx[0x00] = 0x86; card_i430vx[0x01] = 0x80; /*Intel*/ + card_i430vx[0x02] = 0x30; card_i430vx[0x03] = 0x70; /*82437VX*/ + card_i430vx[0x04] = 0x06; card_i430vx[0x05] = 0x00; + card_i430vx[0x06] = 0x00; card_i430vx[0x07] = 0x02; + card_i430vx[0x08] = 0x00; /*A0 stepping*/ + card_i430vx[0x09] = 0x00; card_i430vx[0x0a] = 0x00; card_i430vx[0x0b] = 0x06; + card_i430vx[0x52] = 0x42; /*256kb PLB cache*/ + card_i430vx[0x53] = 0x14; + card_i430vx[0x56] = 0x52; /*DRAM control*/ + card_i430vx[0x57] = 0x01; + card_i430vx[0x60] = card_i430vx[0x61] = card_i430vx[0x62] = card_i430vx[0x63] = card_i430vx[0x64] = 0x02; + card_i430vx[0x67] = 0x11; + card_i430vx[0x69] = 0x03; + card_i430vx[0x70] = 0x20; + card_i430vx[0x72] = 0x02; + card_i430vx[0x74] = 0x0e; + card_i430vx[0x78] = 0x23; +} diff --git a/src/i430vx.h b/src/i430vx.h new file mode 100644 index 000000000..af115bea6 --- /dev/null +++ b/src/i430vx.h @@ -0,0 +1 @@ +void i430vx_init(); diff --git a/src/i440fx.c b/src/i440fx.c new file mode 100644 index 000000000..932b1cd4a --- /dev/null +++ b/src/i440fx.c @@ -0,0 +1,130 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "i440fx.h" + +static uint8_t card_i440fx[256]; + +static void i440fx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i440fx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i440fx[0x59] ^ val) & 0xf0) + { + i440fx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + // pclog("i440fx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i440fx[0x5a] ^ val) & 0x0f) + i440fx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i440fx[0x5a] ^ val) & 0xf0) + i440fx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i440fx[0x5b] ^ val) & 0x0f) + i440fx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i440fx[0x5b] ^ val) & 0xf0) + i440fx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i440fx[0x5c] ^ val) & 0x0f) + i440fx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i440fx[0x5c] ^ val) & 0xf0) + i440fx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i440fx[0x5d] ^ val) & 0x0f) + i440fx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i440fx[0x5d] ^ val) & 0xf0) + i440fx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i440fx[0x5e] ^ val) & 0x0f) + i440fx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i440fx[0x5e] ^ val) & 0xf0) + i440fx_map(0xe4000, 0x04000, val >> 4); + // pclog("i440fx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i440fx[0x5f] ^ val) & 0x0f) + i440fx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i440fx[0x5f] ^ val) & 0xf0) + i440fx_map(0xec000, 0x04000, val >> 4); + // pclog("i440fx_write : PAM6 write %02X\n", val); + break; + } + + card_i440fx[addr] = val; +} + +uint8_t i440fx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i440fx[addr]; +} + + +void i440fx_init() +{ + pci_add_specific(0, i440fx_read, i440fx_write, NULL); + + memset(card_i440fx, 0, 256); + card_i440fx[0x00] = 0x86; card_i440fx[0x01] = 0x80; /*Intel*/ + card_i440fx[0x02] = 0x37; card_i440fx[0x03] = 0x12; /*82441FX*/ + card_i440fx[0x04] = 0x03; card_i440fx[0x05] = 0x01; + card_i440fx[0x06] = 0x00; card_i440fx[0x07] = 0x00; + card_i440fx[0x08] = 0x02; /*A0 stepping*/ + card_i440fx[0x09] = 0x00; card_i440fx[0x0a] = 0x00; card_i440fx[0x0b] = 0x06; + card_i440fx[0x2c] = 0xf4; + card_i440fx[0x2d] = 0x1a; + card_i440fx[0x2e] = 0x00; + card_i440fx[0x2f] = 0x11; + // card_i440fx[0x53] = 0x80; + // card_i440fx[0x55] = 0x11; + card_i440fx[0x57] = 0x10; + card_i440fx[0x58] = 0x00; + card_i440fx[0x59] = 0x10; + card_i440fx[0x5a] = card_i440fx[0x5b] = card_i440fx[0x5c] = card_i440fx[0x5d] = card_i440fx[0x5e] = 0x11; + card_i440fx[0x5f] = 0x31; + // card_i440fx[0x60] = card_i440fx[0x61] = card_i440fx[0x62] = card_i440fx[0x63] = card_i440fx[0x64] = card_i440fx[0x65] = card_i440fx[0x66] = card_i440fx[0x67] = 0x02; + // card_i440fx[0x70] = 0x20; + // card_i440fx[0x71] = 0x10; + card_i440fx[0x72] = 0x0A; +} diff --git a/src/i440fx.h b/src/i440fx.h new file mode 100644 index 000000000..052a938e6 --- /dev/null +++ b/src/i440fx.h @@ -0,0 +1 @@ +void i440fx_init(); diff --git a/src/ibm.h b/src/ibm.h new file mode 100644 index 000000000..3693f139c --- /dev/null +++ b/src/ibm.h @@ -0,0 +1,551 @@ +#include +#include +#include +#define printf pclog + +/*Memory*/ +uint8_t *ram,*vram; + +uint32_t rammask; + +int readlookup[256],readlookupp[256]; +uintptr_t *readlookup2; +int readlnext; +int writelookup[256],writelookupp[256]; +uintptr_t *writelookup2; +int writelnext; + +extern int mmu_perm; + +#define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a))) +#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE)?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC)?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) + +//#define writememb(a,v) if (writelookup2[(a)>>12]==0xFFFFFFFF) writemembl(a,v); else ram[writelookup2[(a)>>12]+((a)&0xFFF)]=v +//#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v +//#define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememll(s,a,v); else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v +//#define readmemb(a) ((isram[((a)>>16)&255] && !(cr0>>31))?ram[a&0xFFFFFF]:readmembl(a)) +//#define writememb(a,v) if (isram[((a)>>16)&255] && !(cr0>>31)) ram[a&0xFFFFFF]=v; else writemembl(a,v) + +//void writememb(uint32_t addr, uint8_t val); +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint8_t readmemb386l(uint32_t seg, uint32_t addr); +void writememb386l(uint32_t seg, uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t seg, uint32_t addr); +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t seg, uint32_t addr); +void writememll(uint32_t seg, uint32_t addr, uint32_t val); +uint64_t readmemql(uint32_t seg, uint32_t addr); +void writememql(uint32_t seg, uint32_t addr, uint64_t val); + +uint8_t *getpccache(uint32_t a); + +uint32_t mmutranslatereal(uint32_t addr, int rw); + +void addreadlookup(uint32_t virt, uint32_t phys); +void addwritelookup(uint32_t virt, uint32_t phys); + + +/*IO*/ +uint8_t inb(uint16_t port); +void outb(uint16_t port, uint8_t val); +uint16_t inw(uint16_t port); +void outw(uint16_t port, uint16_t val); +uint32_t inl(uint16_t port); +void outl(uint16_t port, uint32_t val); + +FILE *romfopen(char *fn, char *mode); +extern int shadowbios,shadowbios_write; +extern int cache; +extern int mem_size; +extern int readlnum,writelnum; +extern int memwaitstate; + + +/*Processor*/ +#define EAX cpu_state.regs[0].l +#define ECX cpu_state.regs[1].l +#define EDX cpu_state.regs[2].l +#define EBX cpu_state.regs[3].l +#define ESP cpu_state.regs[4].l +#define EBP cpu_state.regs[5].l +#define ESI cpu_state.regs[6].l +#define EDI cpu_state.regs[7].l +#define AX cpu_state.regs[0].w +#define CX cpu_state.regs[1].w +#define DX cpu_state.regs[2].w +#define BX cpu_state.regs[3].w +#define SP cpu_state.regs[4].w +#define BP cpu_state.regs[5].w +#define SI cpu_state.regs[6].w +#define DI cpu_state.regs[7].w +#define AL cpu_state.regs[0].b.l +#define AH cpu_state.regs[0].b.h +#define CL cpu_state.regs[1].b.l +#define CH cpu_state.regs[1].b.h +#define DL cpu_state.regs[2].b.l +#define DH cpu_state.regs[2].b.h +#define BL cpu_state.regs[3].b.l +#define BH cpu_state.regs[3].b.h + +typedef union +{ + uint32_t l; + uint16_t w; + struct + { + uint8_t l,h; + } b; +} x86reg; + +struct +{ + x86reg regs[8]; + + int flags_op; + uint32_t flags_res; + uint32_t flags_op1, flags_op2; + + uint32_t pc; +} cpu_state; + +/*x86reg regs[8];*/ + +uint16_t flags,eflags; +uint32_t /*cs,ds,es,ss,*/oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; +//uint16_t msw; + +extern int ins,output; +extern int cycdiff; + +typedef struct +{ + uint32_t base; + uint32_t limit; + uint8_t access; + uint16_t seg; + uint32_t limit_low, limit_high; + int checked; /*Non-zero if selector is known to be valid*/ +} x86seg; + +x86seg gdt,ldt,idt,tr; +x86seg _cs,_ds,_es,_ss,_fs,_gs; +x86seg _oldds; + +extern x86seg *ea_seg; + +uint32_t pccache; +uint8_t *pccache2; +/*Segments - + _cs,_ds,_es,_ss are the segment structures + CS,DS,ES,SS is the 16-bit data + cs,ds,es,ss are defines to the bases*/ +//uint16_t CS,DS,ES,SS; +#define CS _cs.seg +#define DS _ds.seg +#define ES _es.seg +#define SS _ss.seg +#define FS _fs.seg +#define GS _gs.seg +#define cs _cs.base +#define ds _ds.base +#define es _es.base +#define ss _ss.base +#define seg_fs _fs.base +#define gs _gs.base + +#define CPL ((_cs.access>>5)&3) + +void loadseg(uint16_t seg, x86seg *s); +void loadcs(uint16_t seg); + +union +{ + uint32_t l; + uint16_t w; +} CR0; + +#define cr0 CR0.l +#define msw CR0.w + +uint32_t cr2, cr3, cr4; +uint32_t dr[8]; + +#define C_FLAG 0x0001 +#define P_FLAG 0x0004 +#define A_FLAG 0x0010 +#define Z_FLAG 0x0040 +#define N_FLAG 0x0080 +#define T_FLAG 0x0100 +#define I_FLAG 0x0200 +#define D_FLAG 0x0400 +#define V_FLAG 0x0800 +#define NT_FLAG 0x4000 +#define VM_FLAG 0x0002 /*In EFLAGS*/ + +#define WP_FLAG 0x10000 /*In CR0*/ + +#define IOPL ((flags>>12)&3) + +#define IOPLp ((!(msw&1)) || (CPL<=IOPL)) +//#define IOPLp 1 + +//#define IOPLV86 ((!(msw&1)) || (CPL<=IOPL)) +extern int cycles; +extern int cycles_lost; +extern int is486; +extern uint8_t opcode; +extern int insc; +extern int fpucount; +extern float mips,flops; +extern int clockrate; +extern int cgate16; +extern int CPUID; + +extern int cpl_override; + +/*Timer*/ +typedef struct PIT +{ + uint32_t l[3]; + int c[3]; + uint8_t m[3]; + uint8_t ctrl,ctrls[3]; + int wp,rm[3],wm[3]; + uint16_t rl[3]; + int thit[3]; + int delay[3]; + int rereadlatch[3]; + int gate[3]; + int out[3]; + int running[3]; + int enabled[3]; + int newcount[3]; + int count[3]; + int using_timer[3]; + int initial[3]; + int latched[3]; + int disabled[3]; + + uint8_t read_status[3]; + int do_read_status[3]; +} PIT; + +PIT pit; +void setpitclock(float clock); +int pitcount; + +float pit_timer0_freq(); + + + +/*DMA*/ +typedef struct DMA +{ + uint16_t ab[4],ac[4]; + uint16_t cb[4]; + int cc[4]; + int wp; + uint8_t m,mode[4]; + uint8_t page[4]; + uint8_t stat; + uint8_t command; +} DMA; + +DMA dma,dma16; + + +/*PPI*/ +typedef struct PPI +{ + int s2; + uint8_t pa,pb; +} PPI; + +PPI ppi; +extern int key_inhibit; + + +/*PIC*/ +typedef struct PIC +{ + uint8_t icw1,icw4,mask,ins,pend,mask2; + int icw; + uint8_t vector; + int read; +} PIC; + +PIC pic,pic2; +extern int pic_intpending; +int intcount; + + +int disctime; +char discfns[2][256]; +int driveempty[2]; + +#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_INCOLOR) && (romset=ROM_IBMAT)) +#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && gfxcard!=GFX_INCOLOR && gfxcard!=GFX_NEW_CGA && gfxcard!=GFX_COMPAQ_EGA && gfxcard!=GFX_SUPER_EGA && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) +#define PCJR (romset == ROM_IBMPCJR) +#define AMIBIOS (romset==ROM_AMI386 || romset==ROM_AMI486 || romset == ROM_WIN486) + +int GAMEBLASTER, GUS, SSI2001, voodoo_enabled; +extern int AMSTRAD, AT, is286, is386, PCI, TANDY; + +enum +{ + ROM_IBMPC = 0, /*301 keyboard error, 131 cassette (!!!) error*/ + ROM_IBMXT, /*301 keyboard error*/ + ROM_IBMPCJR, + ROM_GENXT, /*'Generic XT BIOS'*/ + ROM_DTKXT, + ROM_EUROPC, + ROM_OLIM24, + ROM_TANDY, + ROM_PC1512, + ROM_PC200, + ROM_PC1640, + ROM_PC2086, + ROM_PC3086, + ROM_AMIXT, /*XT Clone with AMI BIOS*/ + ROM_LTXT, + ROM_LXT3, + ROM_PX386, + ROM_DTK386, + ROM_PXXT, + ROM_JUKOPC, + ROM_TANDY1000HX, + ROM_TANDY1000SL2, + ROM_IBMAT, + ROM_CMDPC30, + ROM_AMI286, + ROM_AWARD286, + ROM_DELL200, + ROM_MISC286, + ROM_IBMAT386, + ROM_ACER386, + ROM_MEGAPC, + ROM_AMI386, + ROM_AMI486, + ROM_WIN486, + ROM_PCI486, + ROM_SIS496, + ROM_430VX, + ROM_ENDEAVOR, + ROM_REVENGE, + ROM_IBMPS1_2011, + ROM_DESKPRO_386, + ROM_IBMPS1_2121, + + ROM_DTK486, /*DTK PKM-0038S E-2 / SiS 471 / Award BIOS / SiS 85C471*/ + ROM_VLI486SV2G, /*ASUS VL/I-486SV2G / SiS 471 / Award BIOS / SiS 85C471*/ + ROM_R418, /*Rise Computer R418 / SiS 496/497 / Award BIOS / SMC FDC37C665*/ + ROM_586MC1, /*Micro Star 586MC1 MS-5103 / 430LX / Award BIOS*/ + ROM_PLATO, /*Intel Premiere/PCI II / 430NX / AMI BIOS / SMC FDC37C665*/ + ROM_MB500N, /*PC Partner MB500N / 430FX / Award BIOS / SMC FDC37C665*/ + ROM_P54TP4XE, /*ASUS P/I-P55TP4XE / 430FX / Award BIOS / SMC FDC37C665*/ + ROM_ACERM3A, /*Acer M3A / 430HX / Acer BIOS / SMC FDC37C932FR*/ + ROM_ACERV35N, /*Acer V35N / 430HX / Acer BIOS / SMC FDC37C932FR*/ + ROM_P55T2P4, /*ASUS P/I-P55T2P4 / 430HX / Award BIOS / Winbond W8387F*/ + ROM_P55TVP4, /*ASUS P/I-P55TVP4 / 430HX / Award BIOS / Winbond W8387F*/ + ROM_P55VA, /*Epox P55-VA / 430VX / Award BIOS / SMC FDC37C932FR*/ + + ROM_440FX, /*Unknown / 440FX / Award BIOS / SMC FDC37C665*/ + ROM_KN97, /*ASUS KN-97 / 440FX / Award BIOS / Winbond W8387F*/ + + ROM_MAX +}; + +extern int romspresent[ROM_MAX]; + +int hasfpu; +int romset; + +enum +{ + GFX_CGA = 0, + GFX_MDA, + GFX_HERCULES, + GFX_EGA, /*Using IBM EGA BIOS*/ + GFX_TVGA, /*Using Trident TVGA8900D BIOS*/ + GFX_ET4000, /*Tseng ET4000*/ + GFX_ET4000W32, /*Tseng ET4000/W32p (Diamond Stealth 32)*/ + GFX_BAHAMAS64, /*S3 Vision864 (Paradise Bahamas 64)*/ + GFX_N9_9FX, /*S3 764/Trio64 (Number Nine 9FX)*/ + GFX_VIRGE, /*S3 Virge*/ + GFX_TGUI9440, /*Trident TGUI9440*/ + GFX_VGA, /*IBM VGA*/ + GFX_VGAEDGE16, /*ATI VGA Edge-16 (18800-1)*/ + GFX_VGACHARGER, /*ATI VGA Charger (28800-5)*/ + GFX_OTI067, /*Oak OTI-067*/ + GFX_MACH64GX, /*ATI Graphics Pro Turbo (Mach64)*/ + GFX_CL_GD5429, /*Cirrus Logic CL-GD5429*/ + GFX_VIRGEDX, /*S3 Virge/DX*/ + GFX_PHOENIX_TRIO32, /*S3 732/Trio32 (Phoenix)*/ + GFX_PHOENIX_TRIO64, /*S3 764/Trio64 (Phoenix)*/ + GFX_INCOLOR, /* Hercules InColor */ + GFX_NEW_CGA, + GFX_ET4000W32C, /*Tseng ET4000/W32p (Cardex) */ + GFX_COMPAQ_EGA, /*Compaq EGA*/ + GFX_SUPER_EGA, /*Using Chips & Technologies SuperEGA BIOS*/ + GFX_COMPAQ_VGA, /*Compaq/Paradise VGA*/ + GFX_MIRO_VISION964, /*S3 Vision964 (Miro Crystal)*/ + GFX_CL_GD5446, /*Cirrus Logic CL-GD5446*/ + GFX_VGAWONDERXL, /*Compaq ATI VGA Wonder XL (28800-5)*/ + GFX_WD90C11, /*Paradise WD90C11*/ + GFX_OTI077, /*Oak OTI-077*/ + GFX_MAX +}; + +extern int gfx_present[GFX_MAX]; + +int gfxcard; + +int cpuspeed; + + +/*Video*/ +void (*pollvideo)(); +void pollega(); +int readflash; +uint8_t hercctrl; +int slowega,egacycles,egacycles2; +extern uint8_t gdcreg[16]; +extern int egareads,egawrites; +extern int cga_comp; +extern int vid_resize; +extern int vid_api; +extern int winsizex,winsizey; +extern int chain4; + +uint8_t readvram(uint16_t addr); +void writevram(uint16_t addr, uint8_t val); +void writevramgen(uint16_t addr, uint8_t val); + +uint8_t readtandyvram(uint16_t addr); +void writetandy(uint16_t addr, uint8_t val); +void writetandyvram(uint16_t addr, uint8_t val); + +extern int et4k_b8000; +extern int changeframecount; +extern uint8_t changedvram[(8192*1024)/1024]; + +void writeega_chain4(uint32_t addr, uint8_t val); +extern uint32_t svgarbank,svgawbank; + +/*Serial*/ +extern int mousedelay; + + +/*Sound*/ +uint8_t spkstat; + +float spktime; +int rtctime; +int soundtime,gustime,gustime2,vidtime; +int ppispeakon; +float CGACONST; +float MDACONST; +float VGACONST1,VGACONST2; +float RTCCONST; +int gated,speakval,speakon; + +#define SOUNDBUFLEN (48000/10) + + +/*Sound Blaster*/ +/*int sbenable,sblatchi,sblatcho,sbcount,sb_enable_i,sb_count_i; +int16_t sbdat;*/ +void setsbclock(float clock); + +#define SADLIB 1 /*No DSP*/ +#define SB1 2 /*DSP v1.05*/ +#define SB15 3 /*DSP v2.00*/ +#define SB2 4 /*DSP v2.01 - needed for high-speed DMA*/ +#define SBPRO 5 /*DSP v3.00*/ +#define SBPRO2 6 /*DSP v3.02 + OPL3*/ +#define SB16 7 /*DSP v4.05 + OPL3*/ +#define SADGOLD 8 /*AdLib Gold*/ +#define SND_WSS 9 /*Windows Sound System*/ +#define SND_PAS16 10 /*Pro Audio Spectrum 16*/ + +int sbtype; + +int clocks[3][12][4]; +int at70hz; + +char pcempath[512]; + + +/*Hard disc*/ + +typedef struct +{ + FILE *f; + int spt,hpc; /*Sectors per track, heads per cylinder*/ + int tracks; +} PcemHDC; + +PcemHDC hdc[4]; + +/*Keyboard*/ +int keybsenddelay; + + +/*CD-ROM*/ +extern int cdrom_drive; +extern int old_cdrom_drive; +extern int idecallback[3]; +extern int cdrom_enabled; + +#define CD_STATUS_EMPTY 0 +#define CD_STATUS_DATA_ONLY 1 +#define CD_STATUS_PLAYING 2 +#define CD_STATUS_PAUSED 3 +#define CD_STATUS_STOPPED 4 + +extern uint32_t atapi_get_cd_channel(int channel); +extern uint32_t atapi_get_cd_volume(int channel); + +void pclog(const char *format, ...); +extern int nmi; + +extern int times; + + +extern float isa_timing, bus_timing; + +extern int frame; + + +uint8_t *vramp; + +uint64_t timer_read(); +extern uint64_t timer_freq; + + +void loadconfig(char *fn); + +extern int infocus; + +void onesec(); + +void resetpc_cad(); + +extern int start_in_fullscreen; +extern int window_w, window_h, window_x, window_y, window_remember; +extern int mouse_always_serial; + +extern uint64_t pmc[2]; + +extern uint16_t temp_seg_data[4]; + +extern uint16_t cs_msr; +extern uint32_t esp_msr; +extern uint32_t eip_msr; + +/* For the AMD K6. */ +extern uint64_t star; + +#define FPU_CW_Reserved_Bits (0xe0c0) diff --git a/src/ide.c b/src/ide.c new file mode 100644 index 000000000..bb7fc709f --- /dev/null +++ b/src/ide.c @@ -0,0 +1,3206 @@ +/*RPCemu v0.6 by Tom Walker + IDE emulation*/ +//#define RPCEMU_IDE + +#define CDROM_ISO 200 +#define IDE_TIME (5 * 100 * (1 << TIMER_SHIFT)) + +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include + +#include + +#ifdef RPCEMU_IDE + #include "rpcemu.h" + #include "iomd.h" + #include "arm.h" +#else + #include "ibm.h" + #include "io.h" + #include "pic.h" + #include "timer.h" +#endif +#include "ide.h" + +/* Bits of 'atastat' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +/* ATA Commands */ +#define WIN_SRST 0x08 /* ATAPI Device Reset */ +#define WIN_RECAL 0x10 +#define WIN_RESTORE WIN_RECAL +#define WIN_READ 0x20 /* 28-Bit Read */ +#define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry*/ +#define WIN_WRITE 0x30 /* 28-Bit Write */ +#define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write */ +#define WIN_VERIFY 0x40 /* 28-Bit Verify */ +#define WIN_VERIFY_ONCE 0x41 /* Added by OBattler - deprected older ATA command, according to the specification I found, it is identical to 0x40 */ +#define WIN_FORMAT 0x50 +#define WIN_SEEK 0x70 +#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */ +#define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */ +#define WIN_READ_MULTIPLE 0xC4 +#define WIN_WRITE_MULTIPLE 0xC5 +#define WIN_SET_MULTIPLE_MODE 0xC6 +#define WIN_READ_DMA 0xC8 +#define WIN_WRITE_DMA 0xCA +#define WIN_SETIDLE1 0xE3 +#define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */ + +/* ATAPI Commands */ +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_READ_6 0x08 +#define GPCMD_INQUIRY 0x12 +#define GPCMD_MODE_SELECT_6 0x15 +#define GPCMD_MODE_SENSE_6 0x1a +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_CDROM_CAPACITY 0x25 +#define GPCMD_READ_10 0x28 +#define GPCMD_SEEK 0x2b +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_READ_DISC_INFORMATION 0x51 +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PLAY_AUDIO_12 0xa5 +#define GPCMD_READ_12 0xa8 +#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_READ_CD 0xbe +#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* ATAPI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* ATAPI Additional Sense Codes */ +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 + +#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11 +#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 +#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 + +/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). + Not that it means anything */ +#define CDROM_SPEED 706 + +/** Evaluate to non-zero if the currently selected drive is an ATAPI device */ +#define IDE_DRIVE_IS_CDROM(ide) (ide->type == IDE_CDROM) +/* +\ + (!ide.drive)*/ + +/* Some generally useful CD-ROM information */ +#define CD_MINS 75 /* max. minutes per CD */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) + +/* Event notification classes for GET EVENT STATUS NOTIFICATION */ +#define GESN_NO_EVENTS 0 +#define GESN_OPERATIONAL_CHANGE 1 +#define GESN_POWER_MANAGEMENT 2 +#define GESN_EXTERNAL_REQUEST 3 +#define GESN_MEDIA 4 +#define GESN_MULTIPLE_HOSTS 5 +#define GESN_DEVICE_BUSY 6 + +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +/* + * The MMC values are not IDE specific and might need to be moved + * to a common header if they are also needed for the SCSI emulation + */ + +/* Profile list from MMC-6 revision 1 table 91 */ +#define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_CD_ROM 0x0008 +#define MMC_PROFILE_CD_R 0x0009 +#define MMC_PROFILE_CD_RW 0x000A +#define MMC_PROFILE_DVD_ROM 0x0010 +#define MMC_PROFILE_DVD_R_SR 0x0011 +#define MMC_PROFILE_DVD_RAM 0x0012 +#define MMC_PROFILE_DVD_RW_RO 0x0013 +#define MMC_PROFILE_DVD_RW_SR 0x0014 +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 +#define MMC_PROFILE_DVD_RW_DL 0x0017 +#define MMC_PROFILE_DVD_DDR 0x0018 +#define MMC_PROFILE_DVD_PLUS_RW 0x001A +#define MMC_PROFILE_DVD_PLUS_R 0x001B +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B +#define MMC_PROFILE_BD_ROM 0x0040 +#define MMC_PROFILE_BD_R_SRM 0x0041 +#define MMC_PROFILE_BD_R_RRM 0x0042 +#define MMC_PROFILE_BD_RE 0x0043 +#define MMC_PROFILE_HDDVD_ROM 0x0050 +#define MMC_PROFILE_HDDVD_R 0x0051 +#define MMC_PROFILE_HDDVD_RAM 0x0052 +#define MMC_PROFILE_HDDVD_RW 0x0053 +#define MMC_PROFILE_HDDVD_R_DL 0x0058 +#define MMC_PROFILE_HDDVD_RW_DL 0x005A +#define MMC_PROFILE_INVALID 0xFFFF + +#define NONDATA 4 +#define CHECK_READY 2 +#define ALLOW_UA 1 + +/* Table of all ATAPI commands and their flags, needed for the new disc change / not ready handler. */ +uint8_t atapi_cmd_table[0x100] = +{ + [GPCMD_TEST_UNIT_READY] = CHECK_READY | NONDATA, + [GPCMD_REQUEST_SENSE] = ALLOW_UA, + [GPCMD_READ_6] = CHECK_READY, + [GPCMD_INQUIRY] = ALLOW_UA, + [GPCMD_MODE_SELECT_6] = 0, + [GPCMD_MODE_SENSE_6] = 0, + [GPCMD_START_STOP_UNIT] = 0, + [GPCMD_PREVENT_REMOVAL] = CHECK_READY, + [GPCMD_READ_CDROM_CAPACITY] = CHECK_READY, + [GPCMD_READ_10] = CHECK_READY, + [GPCMD_SEEK] = CHECK_READY | NONDATA, + [GPCMD_READ_SUBCHANNEL] = CHECK_READY, + [GPCMD_READ_TOC_PMA_ATIP] = CHECK_READY | ALLOW_UA, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS */ + [GPCMD_READ_HEADER] = CHECK_READY, + [GPCMD_PLAY_AUDIO_10] = CHECK_READY, +#if 0 + [GPCMD_GET_CONFIGURATION] = ALLOW_UA, +#endif + [GPCMD_PLAY_AUDIO_MSF] = CHECK_READY, + [GPCMD_GET_EVENT_STATUS_NOTIFICATION] = ALLOW_UA, + [GPCMD_PAUSE_RESUME] = CHECK_READY, + [GPCMD_STOP_PLAY_SCAN] = CHECK_READY, + [GPCMD_READ_DISC_INFORMATION] = CHECK_READY, + [GPCMD_MODE_SELECT_10] = 0, + [GPCMD_MODE_SENSE_10] = 0, + [GPCMD_PLAY_AUDIO_12] = CHECK_READY, + [GPCMD_READ_12] = CHECK_READY, + [GPCMD_SEND_DVD_STRUCTURE] = CHECK_READY, /* Read DVD structure (NOT IMPLEMENTED YET) */ + [GPCMD_SET_SPEED] = 0, + [GPCMD_MECHANISM_STATUS] = 0, + [GPCMD_READ_CD] = CHECK_READY, + [0xBF] = CHECK_READY /* Send DVD structure (NOT IMPLEMENTED YET) */ +}; + +#define IMPLEMENTED 1 + +uint8_t mode_sense_pages[0x40] = +{ + [GPMODE_R_W_ERROR_PAGE] = IMPLEMENTED, + [GPMODE_CDROM_PAGE] = IMPLEMENTED, + [GPMODE_CDROM_AUDIO_PAGE] = IMPLEMENTED, + [GPMODE_CAPABILITIES_PAGE] = IMPLEMENTED, + [GPMODE_ALL_PAGES] = IMPLEMENTED +}; + +ATAPI *atapi; + +int atapi_command = 0; +int readcdmode = 0; + +int cdrom_channel = 2; + +/* Mode sense/select stuff. */ +uint8_t mode_pages_in[256][256]; +#define PAGE_CHANGEABLE 1 +#define PAGE_CHANGED 2 +uint8_t page_flags[256] = +{ + [GPMODE_R_W_ERROR_PAGE] = 0, + [GPMODE_CDROM_PAGE] = 0, + [GPMODE_CDROM_AUDIO_PAGE] = PAGE_CHANGEABLE, + [GPMODE_CAPABILITIES_PAGE] = 0, +}; +uint8_t prefix_len; +uint8_t page_current; + +#define ATAPI_STATUS_IDLE 0 +#define ATAPI_STATUS_COMMAND 1 +#define ATAPI_STATUS_COMPLETE 2 +#define ATAPI_STATUS_DATA 3 +#define ATAPI_STATUS_PACKET_REQ 4 +#define ATAPI_STATUS_PACKET_RECEIVED 5 +#define ATAPI_STATUS_READCD 6 +#define ATAPI_STATUS_REQ_SENSE 7 +#define ATAPI_STATUS_ERROR 0x80 +#define ATAPI_STATUS_ERROR_2 0x81 + +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_CDROM +}; + +typedef struct IDE +{ + int type; + int board; + uint8_t atastat; + uint8_t error; + int secount,sector,cylinder,head,drive,cylprecomp; + uint8_t command; + uint8_t fdisk; + int pos; + int packlen; + int spt,hpc; + int tracks; + int packetstatus; + int cdpos,cdlen; + uint8_t asc; + int reset; + FILE *hdfile; + uint16_t buffer[65536]; + int irqstat; + int service; + int lba; + uint32_t lba_addr; + int skip512; + int blocksize, blockcount; +} IDE; + +IDE ide_drives[6]; + +IDE *ext_ide; + +char ide_fn[4][512]; + +int (*ide_bus_master_read_sector)(int channel, uint8_t *data); +int (*ide_bus_master_write_sector)(int channel, uint8_t *data); +void (*ide_bus_master_set_irq)(int channel); + +static void callnonreadcd(IDE *ide); +static void callreadcd(IDE *ide); +static void atapicommand(int ide_board); + +int idecallback[3] = {0, 0, 0}; + +int cur_ide[3]; + +uint8_t getstat(IDE *ide) { return ide->atastat; } + +static inline void ide_irq_raise(IDE *ide) +{ +// pclog("IDE_IRQ_RAISE\n"); + if (!(ide->fdisk&2)) { +#ifdef RPCEMU_IDE + iomd.irqb.status |= IOMD_IRQB_IDE; + updateirqs(); +#else +// if (ide->board && !ide->irqstat) pclog("IDE_IRQ_RAISE\n"); +#ifdef MAINLINE + picint((ide->board)?(1<<15):(1<<14)); +#else + switch(ide->board) + { + case 0: + picint(1 << 14); + break; + case 1: + picint(1 << 15); + break; + case 2: + picint(1 << 10); + break; + } +#endif + if (ide->board < 2) + { + if (ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board); + } +#endif + } + ide->irqstat=1; + ide->service=1; + // pclog("raising interrupt %i\n", 14 + ide->board); +} + +static inline void ide_irq_lower(IDE *ide) +{ +// pclog("IDE_IRQ_LOWER\n"); +// if (ide.board == 0) { +#ifdef RPCEMU_IDE + iomd.irqb.status &= ~IOMD_IRQB_IDE; + updateirqs(); +#else +#ifdef MAINLINE + picintc((ide->board)?(1<<15):(1<<14)); +#else + switch(ide->board) + { + case 0: + picintc(1 << 14); + break; + case 1: + picintc(1 << 15); + break; + case 2: + picintc(1 << 10); + break; + } +#endif +#endif +// } + ide->irqstat=0; +} + +int get_irq(uint8_t board) +{ + if (board == 0) return 1 << 14; + else if (board == 1) return 1 << 15; + else if (board == 2) return 1 << 10; +} + +void ide_irq_update(IDE *ide) +{ +#ifdef RPCEMU_IDE + if (ide->irqstat && !(iomd.irqb.status & IOMD_IRQB_IDE) && !(ide->fdisk & 2)) { + iomd.irqb.status |= IOMD_IRQB_IDE; + updateirqs(); + } + else if (iomd.irqb.status & IOMD_IRQB_IDE) + { + iomd.irqb.status &= ~IOMD_IRQB_IDE; + updateirqs(); + } +#else +#ifdef MAINLINE + if (ide->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(ide->fdisk & 2)) + picint((ide->board)?(1<<15):(1<<14)); + else if ((pic2.pend|pic2.ins)&0x40) + picintc((ide->board)?(1<<15):(1<<14)); +#else + if (ide->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(ide->fdisk & 2)) + picint(get_irq(ide->board)); + else if ((pic2.pend|pic2.ins)&0x40) + picintc(get_irq(ide->board)); +#endif +#endif +} +/** + * Copy a string into a buffer, padding with spaces, and placing characters as + * if they were packed into 16-bit values, stored little-endian. + * + * @param str Destination buffer + * @param src Source string + * @param len Length of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + */ +static void +ide_padstr(char *str, const char *src, int len) +{ + int i, v; + + for (i = 0; i < len; i++) { + if (*src != '\0') { + v = *src++; + } else { + v = ' '; + } + str[i ^ 1] = v; + } +} + +/** + * Copy a string into a buffer, padding with spaces. Does not add string + * terminator. + * + * @param buf Destination buffer + * @param buf_size Size of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + * @param src Source string + */ +static void +ide_padstr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + + for (i = 0; i < buf_size; i++) { + if (*src != '\0') { + buf[i] = *src++; + } else { + buf[i] = ' '; + } + } +} + +/** + * Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command + */ +static void ide_identify(IDE *ide) +{ + memset(ide->buffer, 0, 512); + + //ide->buffer[1] = 101; /* Cylinders */ + +#ifdef RPCEMU_IDE + ide->buffer[1] = 65535; /* Cylinders */ + ide->buffer[3] = 16; /* Heads */ + ide->buffer[6] = 63; /* Sectors */ +#else + ide->buffer[1] = hdc[cur_ide[ide->board]].tracks; /* Cylinders */ + ide->buffer[3] = hdc[cur_ide[ide->board]].hpc; /* Heads */ + ide->buffer[6] = hdc[cur_ide[ide->board]].spt; /* Sectors */ +#endif + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */ +#ifdef RPCEMU_IDE + ide_padstr((char *) (ide->buffer + 27), "RPCemuHD", 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 27), "PCemHD", 40); /* Model */ +#endif + ide->buffer[20] = 3; /*Buffer type*/ + ide->buffer[21] = 512; /*Buffer size*/ + ide->buffer[47] = 16; /*Max sectors on multiple transfer command*/ + ide->buffer[48] = 1; /*Dword transfers supported*/ + ide->buffer[49] = (1 << 9) | (1 << 8); /* LBA and DMA supported */ + ide->buffer[50] = 0x4000; /* Capabilities */ + ide->buffer[51] = 2 << 8; /*PIO timing mode*/ + ide->buffer[52] = 2 << 8; /*DMA timing mode*/ + ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; +#ifdef RPCEMU_IDE + ide->buffer[60] = (65535 * 16 * 63) & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (65535 * 16 * 63) >> 16; +#else + ide->buffer[60] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) >> 16; +#endif + ide->buffer[63] = 7; /*Multiword DMA*/ + ide->buffer[80] = 0xe; /*ATA-1 to ATA-3 supported*/ +} + +/** + * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command + */ +static void ide_atapi_identify(IDE *ide) +{ + memset(ide->buffer, 0, 512); + + ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */ +#ifdef RPCEMU_IDE + ide_padstr((char *) (ide->buffer + 27), "RPCemuCD", 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 27), "PCemCD", 40); /* Model */ +#endif + ide->buffer[49] = 0x200; /* LBA supported */ +} + +/** + * Fill in ide->buffer with the output of the ATAPI "MODE SENSE" command + * + * @param pos Offset within the buffer to start filling in data + * + * @return Offset within the buffer after the end of the data + */ +static uint32_t ide_atapi_mode_sense(IDE *ide, uint32_t pos, uint8_t type) +{ + uint8_t *buf = (uint8_t *) ide->buffer; +// pclog("ide_atapi_mode_sense %02X\n",type); + if (type==GPMODE_ALL_PAGES || type==GPMODE_R_W_ERROR_PAGE) + { + /* &01 - Read error recovery */ + buf[pos++] = GPMODE_R_W_ERROR_PAGE; + buf[pos++] = 6; /* Page length */ + buf[pos++] = 0; /* Error recovery parameters */ + buf[pos++] = 5; /* Read retry count */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_PAGE) + { + /* &0D - CD-ROM Parameters */ + buf[pos++] = GPMODE_CDROM_PAGE; + buf[pos++] = 6; /* Page length */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 1; /* Inactivity time multiplier *NEEDED BY RISCOS* value is a guess */ + buf[pos++] = 0; buf[pos++] = 60; /* MSF settings */ + buf[pos++] = 0; buf[pos++] = 75; /* MSF settings */ + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_AUDIO_PAGE) + { + /* &0e - CD-ROM Audio Control Parameters */ + buf[pos++] = GPMODE_CDROM_AUDIO_PAGE; + buf[pos++] = 0xE; /* Page length */ + if (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) + { + int i; + + for (i = 0; i < 14; i++) + { + buf[pos++] = mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][i]; + } + } + else + { + buf[pos++] = 4; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; buf[pos++] = 75; /* Logical audio block per second */ + buf[pos++] = 1; /* CDDA Output Port 0 Channel Selection */ + buf[pos++] = 0xFF; /* CDDA Output Port 0 Volume */ + buf[pos++] = 2; /* CDDA Output Port 1 Channel Selection */ + buf[pos++] = 0xFF; /* CDDA Output Port 1 Volume */ + buf[pos++] = 0; /* CDDA Output Port 2 Channel Selection */ + buf[pos++] = 0; /* CDDA Output Port 2 Volume */ + buf[pos++] = 0; /* CDDA Output Port 3 Channel Selection */ + buf[pos++] = 0; /* CDDA Output Port 3 Volume */ + } + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CAPABILITIES_PAGE) + { +// pclog("Capabilities page\n"); + /* &2A - CD-ROM capabilities and mechanical status */ + buf[pos++] = GPMODE_CAPABILITIES_PAGE; + buf[pos++] = 0x12; /* Page length */ + buf[pos++] = 0; buf[pos++] = 0; /* CD-R methods */ + buf[pos++] = 1; /* Supports audio play, not multisession */ + buf[pos++] = 0; /* Some other stuff not supported */ + buf[pos++] = 0; /* Some other stuff not supported (lock state + eject) */ + buf[pos++] = 0; /* Some other stuff not supported */ + buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); + buf[pos++] = (uint8_t) CDROM_SPEED; /* Maximum speed */ + buf[pos++] = 0; buf[pos++] = 2; /* Number of audio levels - on and off only */ + buf[pos++] = 0; buf[pos++] = 0; /* Buffer size - none */ + buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); + buf[pos++] = (uint8_t) CDROM_SPEED; /* Current speed */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Drive digital format */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + } + + return pos; +} + +uint32_t atapi_get_cd_channel(int channel) +{ + return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] : (channel + 1); +} + +uint32_t atapi_get_cd_volume(int channel) +{ + // return ((page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) && (mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] != 0)) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; + return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; +} + +/* + * Return the sector offset for the current register values + */ +static off64_t ide_get_sector(IDE *ide) +{ + if (ide->lba) + { + return (off64_t)ide->lba_addr + ide->skip512; + } + else + { + int heads = ide->hpc; + int sectors = ide->spt; + + return ((((off64_t) ide->cylinder * heads) + ide->head) * + sectors) + (ide->sector - 1) + ide->skip512; + } +} + +/** + * Move to the next sector using CHS addressing + */ +static void ide_next_sector(IDE *ide) +{ + if (ide->lba) + { + ide->lba_addr++; + } + else + { + ide->sector++; + if (ide->sector == (ide->spt + 1)) { + ide->sector = 1; + ide->head++; + if (ide->head == ide->hpc) { + ide->head = 0; + ide->cylinder++; + } + } + } +} + +#ifdef RPCEMU_IDE +static void loadhd(IDE *ide, int d, const char *fn) +{ + char pathname[512]; + + append_filename(pathname, rpcemu_get_datadir(), fn, 512); + + rpclog("Loading %s\n",pathname); + if (ide->hdfile == NULL) { + /* Try to open existing hard disk image */ + ide->hdfile = fopen64(pathname, "rb+"); + if (ide->hdfile == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + ide->hdfile = fopen64(pathname, "wb+"); + if (ide->hdfile == NULL) { + fatal("Cannot create file '%s': %s", + pathname, strerror(errno)); + } + } else { + /* Failed for another reason */ + fatal("Cannot open file '%s': %s", + pathname, strerror(errno)); + } + } + } + + fseek(ide->hdfile, 0xfc1, SEEK_SET); + ide->spt = getc(ide->hdfile); + ide->hpc = getc(ide->hdfile); + ide->skip512 = 1; +// rpclog("First check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]); + if (!ide->spt || !ide->hpc) + { + fseek(ide->hdfile, 0xdc1, SEEK_SET); + ide->spt = getc(ide->hdfile); + ide->hpc = getc(ide->hdfile); +// rpclog("Second check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]); + ide->skip512 = 0; + if (!ide->spt || !ide->hpc) + { + ide->spt=63; + ide->hpc=16; + ide->skip512 = 1; +// rpclog("Final check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]); + } + } + + ide->type = IDE_HDD; + + rpclog("%i %i %i\n",ide->spt,ide->hpc,ide->skip512); +} +#else +static void loadhd(IDE *ide, int d, const char *fn) +{ + if (ide->hdfile == NULL) { + /* Try to open existing hard disk image */ + ide->hdfile = fopen64(fn, "rb+"); + if (ide->hdfile == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + ide->hdfile = fopen64(fn, "wb+"); + if (ide->hdfile == NULL) { + ide->type = IDE_NONE; +/* fatal("Cannot create file '%s': %s", + fn, strerror(errno));*/ + return; + } + } else { + /* Failed for another reason */ + ide->type = IDE_NONE; +/* fatal("Cannot open file '%s': %s", + fn, strerror(errno));*/ + return; + } + } + } + + ide->spt = hdc[d].spt; + ide->hpc = hdc[d].hpc; + ide->tracks = hdc[d].tracks; + ide->type = IDE_HDD; +} +#endif + +void ide_set_signature(IDE *ide) +{ + ide->secount=1; + ide->sector=1; + ide->head=0; + ide->cylinder=(IDE_DRIVE_IS_CDROM(ide) ? 0xEB14 : ((ide->type == IDE_HDD) ? 0 : 0xFFFF)); + if (ide->type == IDE_HDD) ide->drive = 0; +} + +void resetide(void) +{ + int d; + + /* Close hard disk image files (if previously open) */ + for (d = 0; d < 4; d++) { + ide_drives[d].type = IDE_NONE; + if (ide_drives[d].hdfile != NULL) { + fclose(ide_drives[d].hdfile); + ide_drives[d].hdfile = NULL; + } + ide_drives[d].atastat = READY_STAT | DSC_STAT; + ide_drives[d].service = 0; + ide_drives[d].board = (d & 2) ? 1 : 0; + } + + for (d = 4; d < 6; d++) + { + ide_drives[d].type = IDE_NONE; + ide_drives[d].atastat = READY_STAT | DSC_STAT; + ide_drives[d].service = 0; + ide_drives[d].board = 2; + } + + page_flags[GPMODE_CDROM_AUDIO_PAGE] &= 0xFD; /* Clear changed flag for CDROM AUDIO mode page. */ + memset(mode_pages_in[GPMODE_CDROM_AUDIO_PAGE], 0, 256); /* Clear the page itself. */ + + idecallback[0]=idecallback[1]=0; +#ifdef RPCEMU_IDE + loadhd(&ide_drives[0], 0, "hd4.hdf"); + if (!config.cdromenabled) { + loadhd(&ide_drives[1], 1, "hd5.hdf"); + } + else + ide_drives[1].type = IDE_CDROM; +#else + for (d = 0; d < 4; d++) + { + ide_drives[d].packetstatus = 0xFF; + + if ((cdrom_channel == d) && cdrom_enabled) + { + ide_drives[d].type = IDE_CDROM; + } + else + { + loadhd(&ide_drives[d], d, ide_fn[d]); + } + + ide_set_signature(&ide_drives[d]); + } + + /* REMOVE WHEN SUBMITTING TO MAINLINE - START */ + for (d = 4; d < 6; d++) + { + ide_drives[d].packetstatus = 0xFF; + + if ((cdrom_channel == d) && cdrom_enabled) + { + ide_drives[d].type = IDE_CDROM; + } + else + { + ide_drives[d].type = IDE_NONE; + } + + ide_set_signature(&ide_drives[d]); + } + /* REMOVE WHEN SUBMITTING TO MAINLINE - END */ +#endif + + cur_ide[0] = 0; + cur_ide[1] = 2; + + cur_ide[2] = 4; + +// ide_drives[1].type = IDE_CDROM; + + page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED; +} + +int idetimes=0; +void writeidew(int ide_board, uint16_t val) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + + /*Some software issue excess writes after the 12 bytes required by the command, this will have all of them ignored*/ + if (ide->packetstatus && (ide->packetstatus != ATAPI_STATUS_PACKET_REQ)) + return; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed write IDE %04X:%08X\n",CS,pc); + return; + }*/ +#endif +#ifdef _RPCEMU_BIG_ENDIAN + val=(val>>8)|(val<<8); +#endif +// pclog("Write IDEw %04X\n",val); + ide->buffer[ide->pos >> 1] = val; + ide->pos+=2; + + if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ) + { + if ((ide->pos>=prefix_len+4) && (page_flags[page_current] & PAGE_CHANGEABLE)) + { + mode_pages_in[page_current][ide->pos - prefix_len - 4] = ((uint8_t *) ide->buffer)[ide->pos - 2]; + mode_pages_in[page_current][ide->pos - prefix_len - 3] = ((uint8_t *) ide->buffer)[ide->pos - 1]; + } + if (ide->pos>=(ide->packlen+2)) + { + ide->packetstatus = ATAPI_STATUS_PACKET_RECEIVED; + timer_process(); + idecallback[ide_board]=6*IDE_TIME; + timer_update_outstanding(); +// pclog("Packet over!\n"); + ide_irq_lower(ide); + } + return; + } + else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) + return; + else if (ide->command == WIN_PACKETCMD && ide->pos>=0xC) + { + ide->pos=0; + ide->atastat = BUSY_STAT; + ide->packetstatus = ATAPI_STATUS_COMMAND; +/* idecallback[ide_board]=6*IDE_TIME;*/ + timer_process(); + callbackide(ide_board); + timer_update_outstanding(); +// idecallback[ide_board]=60*IDE_TIME; +// if ((ide->buffer[0]&0xFF)==0x43) idecallback[ide_board]=1*IDE_TIME; +// pclog("Packet now waiting!\n"); +/* if (ide->buffer[0]==0x243) + { + idetimes++; + output=3; + }*/ + } + else if (ide->pos>=512) + { + ide->pos=0; + ide->atastat = BUSY_STAT; + timer_process(); + if (ide->command == WIN_WRITE_MULTIPLE) + callbackide(ide_board); + else + idecallback[ide_board]=6*IDE_TIME; + timer_update_outstanding(); + } +} + +void writeidel(int ide_board, uint32_t val) +{ +// pclog("WriteIDEl %08X\n", val); + writeidew(ide_board, val); + writeidew(ide_board, val >> 16); +} + +void writeide(int ide_board, uint16_t addr, uint8_t val) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed write IDE %04X:%08X\n",CS,pc); + return; + }*/ +#endif +// if ((cr0&1) && !(eflags&VM_FLAG)) +// pclog("WriteIDE %04X %02X from %04X(%08X):%08X %i\n", addr, val, CS, cs, pc, ins); +// return; + addr|=0x80; + /* ONLY FOR EXPERIMENTAL */ + addr|=0x10; /* 1F0 | 10 = 1F0, 1E8 | 10 = 1F8 */ + addr&=0xFFF7; /* 1F0 & FFF7 = 1F0, 1F8 | FFF7 = 1F0 */ +// if (ide_board) pclog("Write IDEb %04X %02X %04X(%08X):%04X %i %02X %02X\n",addr,val,CS,cs,pc,ins,ide->atastat,ide_drives[0].atastat); + /*if (idedebug) */ +// pclog("Write IDE %08X %02X %04X:%08X\n",addr,val,CS,pc); +// int c; +// rpclog("Write IDE %08X %02X %08X %08X\n",addr,val,PC,armregs[12]); + + if (ide->type == IDE_NONE && (addr == 0x1f0 || addr == 0x1f7)) return; + + switch (addr) + { + case 0x1F0: /* Data */ + writeidew(ide_board, val | (val << 8)); + return; + + case 0x1F1: /* Features */ + ide->cylprecomp = val; + ide_other->cylprecomp = val; + return; + + case 0x1F2: /* Sector count */ + ide->secount = val; + ide_other->secount = val; + return; + + case 0x1F3: /* Sector */ + ide->sector = val; + ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; + ide_other->sector = val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; + return; + + case 0x1F4: /* Cylinder low */ + ide->cylinder = (ide->cylinder & 0xFF00) | val; + ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); + ide_other->cylinder = (ide_other->cylinder&0xFF00) | val; + ide_other->lba_addr = (ide_other->lba_addr&0xFFF00FF) | (val << 8); +// pclog("Write cylinder low %02X\n",val); + return; + + case 0x1F5: /* Cylinder high */ + ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); + ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); + ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); + ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); + return; + + case 0x1F6: /* Drive/Head */ +/* if (val==0xB0) + { + dumpregs(); + exit(-1); + }*/ + + if (cur_ide[ide_board] != ((val>>4)&1)+(ide_board<<1)) + { + cur_ide[ide_board]=((val>>4)&1)+(ide_board<<1); + + if (ide->reset || ide_other->reset) + { + ide->atastat = ide_other->atastat = READY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + // ide->blocksize = ide_other->blocksize = 0; + if (IDE_DRIVE_IS_CDROM(ide)) + ide->cylinder=0xEB14; + if (IDE_DRIVE_IS_CDROM(ide_other)) + ide_other->cylinder=0xEB14; + + idecallback[ide_board] = 0; + timer_update_outstanding(); + return; + } + + ide = &ide_drives[cur_ide[ide_board]]; + } + + ide->head = val & 0xF; + ide->lba = val & 0x40; + ide_other->head = val & 0xF; + ide_other->lba = val & 0x40; + + ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); + ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24); + + ide_irq_update(ide); + return; + + case 0x1F7: /* Command register */ + if (ide->type == IDE_NONE) return; +// pclog("IDE command %02X drive %i\n",val,ide.drive); + ide_irq_lower(ide); + ide->command=val; + +// pclog("New IDE command - %02X %i %i\n",ide->command,cur_ide[ide_board],ide_board); + ide->error=0; + switch (val) + { + case WIN_SRST: /* ATAPI Device Reset */ + if (IDE_DRIVE_IS_CDROM(ide)) ide->atastat = BUSY_STAT; + else ide->atastat = READY_STAT; + timer_process(); + idecallback[ide_board]=100*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_RESTORE: + case WIN_SEEK: +// pclog("WIN_RESTORE start\n"); + ide->atastat = READY_STAT; + timer_process(); + idecallback[ide_board]=100*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_READ_MULTIPLE: + if (!ide->blocksize && (ide->type != IDE_CDROM)) + fatal("READ_MULTIPLE - blocksize = 0\n"); +#if 0 + if (ide->lba) pclog("Read Multiple %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Read Multiple %i sectors from sector %i cylinder %i head %i %i\n",ide->secount,ide->sector,ide->cylinder,ide->head,ins); +#endif + ide->blockcount = 0; + + case WIN_READ: + case WIN_READ_NORETRY: + case WIN_READ_DMA: +/* if (ide.secount>1) + { + fatal("Read %i sectors from sector %i cylinder %i head %i\n",ide.secount,ide.sector,ide.cylinder,ide.head); + }*/ +#if 0 + if (ide->lba) pclog("Read %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Read %i sectors from sector %i cylinder %i head %i %i\n",ide->secount,ide->sector,ide->cylinder,ide->head,ins); +#endif + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_WRITE_MULTIPLE: + if (!ide->blocksize && (ide->type != IDE_CDROM)) + fatal("Write_MULTIPLE - blocksize = 0\n"); +#if 0 + if (ide->lba) pclog("Write Multiple %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Write Multiple %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->blockcount = 0; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + /* if (ide.secount>1) + { + fatal("Write %i sectors to sector %i cylinder %i head %i\n",ide.secount,ide.sector,ide.cylinder,ide.head); + }*/ +#if 0 + if (ide->lba) pclog("Write %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Write %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->atastat = DRQ_STAT | DSC_STAT | READY_STAT; + ide->pos=0; + return; + + case WIN_WRITE_DMA: +#if 0 + if (ide->lba) pclog("Write %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Write %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_VERIFY: + case WIN_VERIFY_ONCE: +#if 0 + if (ide->lba) pclog("Read verify %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Read verify %i sectors from sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_FORMAT: +// pclog("Format track %i head %i\n",ide.cylinder,ide.head); + ide->atastat = DRQ_STAT; +// idecallback[ide_board]=200; + ide->pos=0; + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=30*IDE_TIME; + timer_update_outstanding(); +// pclog("SPECIFY\n"); +// output=1; + return; + + case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ + case WIN_PIDENTIFY: /* Identify Packet Device */ + case WIN_SET_MULTIPLE_MODE: /*Set Multiple Mode*/ +// output=1; + case WIN_SETIDLE1: /* Idle */ + ide->atastat = BUSY_STAT; + timer_process(); + callbackide(ide_board); +// idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_IDENTIFY: /* Identify Device */ + case 0xEF: +// output=3; +// timetolive=500; + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + ide->packetstatus = ATAPI_STATUS_IDLE; + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=1;//30*IDE_TIME; + timer_update_outstanding(); + ide->pos=0; + return; + + case 0xF0: + default: + ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide_irq_raise(ide); +/* fatal("Bad IDE command %02X\n", val);*/ + return; + } + + return; + + case 0x3F6: /* Device control */ + if ((ide->fdisk&4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) + { + timer_process(); + idecallback[ide_board]=500*IDE_TIME; + timer_update_outstanding(); + ide->reset = ide_other->reset = 1; + ide->atastat = ide_other->atastat = BUSY_STAT; +// pclog("IDE Reset %i\n", ide_board); + } + ide->fdisk = ide_other->fdisk = val; + ide_irq_update(ide); + return; + } +// fatal("Bad IDE write %04X %02X\n", addr, val); +} + +uint8_t readide(int ide_board, uint16_t addr) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint8_t temp; + uint16_t tempw; + + addr|=0x80; + /* ONLY FOR EXPERIMENTAL */ + addr|=0x10; /* 1F0 | 10 = 1F0, 1E8 | 10 = 1F8 */ + addr&=0xFFF7; /* 1F0 & FFF7 = 1F0, 1F8 | FFF7 = 1F0 */ +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed read IDE %04X:%08X\n",CS,pc); + return 0xFF; + }*/ +#endif +// if ((cr0&1) && !(eflags&VM_FLAG)) +// pclog("ReadIDE %04X from %04X(%08X):%08X\n", addr, CS, cs, pc); +// return 0xFF; + + if (ide->type == IDE_NONE && (addr == 0x1f0 || addr == 0x1f7)) return 0; +// /*if (addr!=0x1F7 && addr!=0x3F6) */pclog("Read IDEb %04X %02X %02X %i %04X:%04X %i %04X\n",addr,ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,pc,ide_board, BX); +//rpclog("Read IDE %08X %08X %02X\n",addr,PC,iomd.irqb.mask); + switch (addr) + { + case 0x1F0: /* Data */ + tempw = readidew(ide_board); +// pclog("Read IDEW %04X\n", tempw); + temp = tempw & 0xff; + break; + + case 0x1F1: /* Error */ +// pclog("Read error %02X\n",ide.error); + temp = ide->error; + break; + + case 0x1F2: /* Sector count */ +// pclog("Read sector count %02X\n",ide->secount); + temp = (uint8_t)ide->secount; + break; + + case 0x1F3: /* Sector */ + temp = (uint8_t)ide->sector; + break; + + case 0x1F4: /* Cylinder low */ +// pclog("Read cyl low %02X\n",ide.cylinder&0xFF); + temp = (uint8_t)(ide->cylinder&0xFF); + break; + + case 0x1F5: /* Cylinder high */ +// pclog("Read cyl low %02X\n",ide.cylinder>>8); + temp = (uint8_t)(ide->cylinder>>8); + break; + + case 0x1F6: /* Drive/Head */ + temp = (uint8_t)(ide->head | ((cur_ide[ide_board] & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); + break; + + case 0x1F7: /* Status */ + if (ide->type == IDE_NONE) + { +// pclog("Return status 00\n"); + temp = 0; + break; + } + ide_irq_lower(ide); + if (ide->type == IDE_CDROM) + { +// pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0)); + temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + } + else + { +// && ide->service) return ide.atastat[ide.board]|SERVICE_STAT; +// pclog("Return status %02X %04X:%04X %02X %02X\n",ide->atastat, CS ,pc, AH, BH); + temp = ide->atastat; + } + break; + + case 0x3F6: /* Alternate Status */ +// pclog("3F6 read %02X\n",ide.atastat[ide.board]); +// if (output) output=0; + if (ide->type == IDE_NONE) + { +// pclog("Return status 00\n"); + temp = 0; + break; + } + if (ide->type == IDE_CDROM) + { +// pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0)); + temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + } + else + { +// && ide->service) return ide.atastat[ide.board]|SERVICE_STAT; +// pclog("Return status %02X\n",ide->atastat); + temp = ide->atastat; + } + break; + } +// if (ide_board) pclog("Read IDEb %04X %02X %02X %02X %i %04X:%04X %i\n", addr, temp, ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,pc,ide_board); + return temp; +// fatal("Bad IDE read %04X\n", addr); +} + +uint16_t readidew(int ide_board) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint16_t temp; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed read IDEw %04X:%08X\n",CS,pc); + return 0xFFFF; + }*/ +#endif +// return 0xFFFF; +// pclog("Read IDEw %04X %04X:%04X %02X %i %i\n",ide->buffer[ide->pos >> 1],CS,pc,opcode,ins, ide->pos); + +//if (idedebug) pclog("Read IDEW %08X\n",PC); + + temp = ide->buffer[ide->pos >> 1]; + #ifdef _RPCEMU_BIG_ENDIAN + temp=(temp>>8)|(temp<<8); + #endif + ide->pos+=2; + if ((ide->command == WIN_PACKETCMD) && ((ide->packetstatus == ATAPI_STATUS_REQ_SENSE) || (ide->packetstatus==8))) + { + callnonreadcd(ide); + return temp; + } + if ((ide->pos>=512 && ide->command != WIN_PACKETCMD) || (ide->command == WIN_PACKETCMD && ide->pos>=ide->packlen)) + { +// pclog("Over! packlen %i %i\n",ide->packlen,ide->pos); + ide->pos=0; + if (ide->command == WIN_PACKETCMD)// && ide.packetstatus==6) + { +// pclog("Call readCD\n"); + callreadcd(ide); + } + else + { + ide->atastat = READY_STAT | DSC_STAT; + ide->packetstatus = ATAPI_STATUS_IDLE; + if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) + { + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide_next_sector(ide); + ide->atastat = BUSY_STAT; + timer_process(); + if (ide->command == WIN_READ_MULTIPLE) + callbackide(ide_board); + else + idecallback[ide_board]=6*IDE_TIME; + timer_update_outstanding(); +// pclog("set idecallback\n"); +// callbackide(ide_board); + } +// else +// pclog("readidew done %02X\n", ide->atastat); + } + } + } +// pclog("Read IDEw %04X\n",temp); + return temp; +} + +uint32_t readidel(int ide_board) +{ + uint16_t temp; +// pclog("Read IDEl %i\n", ide_board); + temp = readidew(ide_board); + return temp | (readidew(ide_board) << 16); +} + +int times30=0; +void callbackide(int ide_board) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; + off64_t addr; + int c; + ext_ide = ide; +// return; + if (ide->command==0x30) times30++; +// if (times30==2240) output=1; + //if (times30==2471 && ide->command==0xA0) output=1; +///*if (ide_board) */pclog("CALLBACK %02X %i %i %i\n",ide->command,times30,ide->reset,cur_ide[ide_board]); +// if (times30==1294) +// output=1; + if (ide->reset) + { + ide->atastat = ide_other->atastat = READY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + if (IDE_DRIVE_IS_CDROM(ide)) + { + ide->cylinder=0xEB14; + atapi->stop(); + } + if (ide->type == IDE_NONE) + { + ide->cylinder=0xFFFF; + atapi->stop(); + } + if (IDE_DRIVE_IS_CDROM(ide_other)) + { + ide_other->cylinder=0xEB14; + atapi->stop(); + } + if (ide_other->type == IDE_NONE) + { + ide_other->cylinder=0xFFFF; + atapi->stop(); + } +// pclog("Reset callback\n"); + return; + } + switch (ide->command) + { + //Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. + case WIN_SRST: /*ATAPI Device Reset */ + ide->atastat = READY_STAT | DSC_STAT; + ide->error=1; /*Device passed*/ + ide->secount = ide->sector = 1; + ide_set_signature(ide); + if (IDE_DRIVE_IS_CDROM(ide)) + ide->atastat = 0; + ide_irq_raise(ide); + if (IDE_DRIVE_IS_CDROM(ide)) + ide->service = 0; + return; + + case WIN_RESTORE: + case WIN_SEEK: + if (IDE_DRIVE_IS_CDROM(ide)) { + pclog("WIN_RESTORE callback on CD-ROM\n"); + goto abort_cmd; + } +// pclog("WIN_RESTORE callback\n"); + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_READ: + case WIN_READ_NORETRY: + if (IDE_DRIVE_IS_CDROM(ide)) { + ide_set_signature(ide); + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Read %i %i %i %08X\n",ide.cylinder,ide.head,ide.sector,addr); + /* if (ide.cylinder || ide.head) + { + fatal("Read from other cylinder/head"); + }*/ + fseeko64(ide->hdfile, addr, SEEK_SET); + fread(ide->buffer, 512, 1, ide->hdfile); + ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; +// pclog("Read sector callback %i %i %i offset %08X %i left %i %02X\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt,ide.atastat[ide.board]); +// if (addr) output=3; + ide_irq_raise(ide); +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_READ_DMA: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; + fseeko64(ide->hdfile, addr, SEEK_SET); + fread(ide->buffer, 512, 1, ide->hdfile); + ide->pos=0; + + if (ide_bus_master_read_sector) + { + if (ide_bus_master_read_sector(ide_board, (uint8_t *)ide->buffer)) + idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ + else + { + /*DMA successful*/ + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide_next_sector(ide); + ide->atastat = BUSY_STAT; + idecallback[ide_board]=6*IDE_TIME; + } + else + { + ide_irq_raise(ide); + } + } + } +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_READ_MULTIPLE: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Read multiple from %08X %i (%i) %i\n", addr, ide->blockcount, ide->blocksize, ide->secount); + fseeko64(ide->hdfile, addr, SEEK_SET); + fread(ide->buffer, 512, 1, ide->hdfile); + ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + if (!ide->blockcount)// || ide->secount == 1) + { +// pclog("Read multiple int\n"); + ide_irq_raise(ide); + } + ide->blockcount++; + if (ide->blockcount >= ide->blocksize) + ide->blockcount = 0; +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Write sector callback %i %i %i offset %08X %i left %i\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt); + fseeko64(ide->hdfile, addr, SEEK_SET); + fwrite(ide->buffer, 512, 1, ide->hdfile); + ide_irq_raise(ide); + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + } + else + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_WRITE_DMA: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + + if (ide_bus_master_write_sector) + { + if (ide_bus_master_write_sector(ide_board, (uint8_t *)ide->buffer)) + idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ + else + { + /*DMA successful*/ + addr = ide_get_sector(ide) * 512; + fseeko64(ide->hdfile, addr, SEEK_SET); + fwrite(ide->buffer, 512, 1, ide->hdfile); + + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide_next_sector(ide); + ide->atastat = BUSY_STAT; + idecallback[ide_board]=6*IDE_TIME; + } + else + { + ide_irq_raise(ide); + } + } + } +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_WRITE_MULTIPLE: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Write sector callback %i %i %i offset %08X %i left %i\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt); + fseeko64(ide->hdfile, addr, SEEK_SET); + fwrite(ide->buffer, 512, 1, ide->hdfile); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize || ide->secount == 1) + { + ide->blockcount = 0; + ide_irq_raise(ide); + } + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + } + else + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + ide->pos=0; + ide->atastat = READY_STAT | DSC_STAT; +// pclog("Read verify callback %i %i %i offset %08X %i left\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount); + ide_irq_raise(ide); +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_FORMAT: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Format cyl %i head %i offset %08X %08X %08X secount %i\n",ide.cylinder,ide.head,addr,addr>>32,addr,ide.secount); + fseeko64(ide->hdfile, addr, SEEK_SET); + memset(ide->buffer, 0, 512); + for (c=0;csecount;c++) + { + fwrite(ide->buffer, 512, 1, ide->hdfile); + } + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_DRIVE_DIAGNOSTICS: + ide_set_signature(ide); + ide->error=1; /*No error detected*/ + if (IDE_DRIVE_IS_CDROM(ide)) + { + ide->atastat = 0; + } + else + { + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (IDE_DRIVE_IS_CDROM(ide)) { +#ifndef RPCEMU_IDE + pclog("IS CDROM - ABORT\n"); +#endif + goto abort_cmd; + } + ide->spt=ide->secount; + ide->hpc=ide->head+1; + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE +// pclog("SPECIFY - %i sectors per track, %i heads per cylinder %i %i\n",ide->spt,ide->hpc,cur_ide[ide_board],ide_board); +#endif + ide_irq_raise(ide); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + if (IDE_DRIVE_IS_CDROM(ide)) { +// pclog("ATAPI identify\n"); + ide_atapi_identify(ide); + ide->pos=0; + ide->error=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } +// pclog("Not ATAPI\n"); + goto abort_cmd; + + case WIN_SET_MULTIPLE_MODE: + if (IDE_DRIVE_IS_CDROM(ide)) { +#ifndef RPCEMU_IDE + pclog("IS CDROM - ABORT\n"); +#endif + goto abort_cmd; + } + ide->blocksize = ide->secount; + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE + pclog("Set multiple mode - %i\n", ide->blocksize); +#endif + ide_irq_raise(ide); + return; + + case WIN_SETIDLE1: /* Idle */ + case 0xEF: + goto abort_cmd; + + case WIN_IDENTIFY: /* Identify Device */ + if (ide->type == IDE_NONE) + { + goto abort_cmd; + } + if (IDE_DRIVE_IS_CDROM(ide)) + { + ide_set_signature(ide); + goto abort_cmd; + } + else + { + ide_identify(ide); + ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; +// pclog("ID callback\n"); + ide_irq_raise(ide); + } + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + if (!IDE_DRIVE_IS_CDROM(ide)) goto abort_cmd; +// pclog("Packet callback! %i %08X\n",ide->packetstatus,ide); + + if (ide->packetstatus == ATAPI_STATUS_IDLE) + { + readcdmode=0; + ide->pos=0; + ide->secount = (uint8_t)((ide->secount&0xF8)|1); + ide->atastat = READY_STAT | DRQ_STAT |(ide->atastat&ERR_STAT); + //ide_irq_raise(ide); +// pclog("1 Preparing to recieve packet max DRQ count %04X\n",ide->cylinder); + } + else if (ide->packetstatus == ATAPI_STATUS_COMMAND) + { + ide->atastat = BUSY_STAT|(ide->atastat&ERR_STAT); +// pclog("Running ATAPI command 2\n"); + atapicommand(ide_board); +// exit(-1); + } + else if (ide->packetstatus == ATAPI_STATUS_COMPLETE) + { +// pclog("packetstatus==2\n"); + ide->atastat = READY_STAT; + ide->secount=3; + ide_irq_raise(ide); +// if (iomd.irqb.mask&2) output=1; + } + else if (ide->packetstatus == ATAPI_STATUS_DATA) + { + ide->atastat = READY_STAT|DRQ_STAT|(ide->atastat&ERR_STAT); +// rpclog("Recieve data packet 3! %02X\n",ide->atastat); + ide_irq_raise(ide); + ide->packetstatus=0xFF; + } + else if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ) + { + ide->atastat = 0x58 | (ide->atastat & ERR_STAT); +// pclog("Send data packet 4!\n"); + ide_irq_raise(ide); +// ide.packetstatus=5; + ide->pos=2; + } + else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) + { +// pclog("Packetstatus 5 !\n"); + atapicommand(ide_board); + } + else if (ide->packetstatus == ATAPI_STATUS_READCD) /*READ CD callback*/ + { + ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT); +// pclog("Recieve data packet 6!\n"); + ide_irq_raise(ide); +// ide.packetstatus=0xFF; + } + else if (ide->packetstatus == ATAPI_STATUS_REQ_SENSE) /*REQUEST SENSE callback #1*/ + { + pclog("REQUEST SENSE callback #1: setting status to 0x5A\n"); + ide->atastat = 0x58 | (ide->atastat & ERR_STAT); + ide_irq_raise(ide); + } + else if (ide->packetstatus == ATAPI_STATUS_ERROR) /*Error callback*/ + { +// pclog("Packet error\n"); + ide->atastat = READY_STAT | ERR_STAT; + ide_irq_raise(ide); + } + else if (ide->packetstatus == ATAPI_STATUS_ERROR_2) /*Error callback with atastat already set - needed for the disc change stuff.*/ + { + //pclog("Packet check status\n"); + ide->atastat = ERR_STAT; + ide_irq_raise(ide); + } + return; + } + +abort_cmd: + ide->command = 0; + ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide->pos = 0; + ide_irq_raise(ide); +} + +void ide_callback_pri() +{ + idecallback[0] = 0; + callbackide(0); +} + +void ide_callback_sec() +{ + idecallback[1] = 0; + callbackide(1); +} + +void ide_callback_ter() +{ + idecallback[2] = 0; + callbackide(2); +} + +/*ATAPI CD-ROM emulation*/ + +struct +{ + int sensekey,asc,ascq; +} atapi_sense; + +static uint8_t atapi_set_profile(uint8_t *buf, uint8_t *index, uint16_t profile) +{ + uint8_t *buf_profile = buf + 12; /* start of profiles */ + + buf_profile += ((*index) * 4); /* start of indexed profile */ + buf_profile[0] = (profile >> 8) & 0xff; + buf_profile[1] = profile & 0xff; + buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); + + /* each profile adds 4 bytes to the response */ + (*index)++; + buf[11] += 4; /* Additional Length */ + + return 4; +} + +static int atapi_read_structure(IDE *ide, int format, + const uint8_t *packet, uint8_t *buf) +{ + switch (format) { + case 0x0: /* Physical format information */ + { + int layer = packet[6]; + uint64_t total_sectors; + + if (layer != 0) + return -ASC_INV_FIELD_IN_CMD_PACKET; + + total_sectors >>= 2; + if (total_sectors == 0) + return -ASC_MEDIUM_NOT_PRESENT; + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ + buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ + buf[13] = (total_sectors >> 16) & 0xff; + buf[14] = (total_sectors >> 8) & 0xff; + buf[15] = total_sectors & 0xff; + + buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ + buf[17] = (total_sectors >> 16) & 0xff; + buf[18] = (total_sectors >> 8) & 0xff; + buf[19] = total_sectors & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048+2)>>8)&0xff; + buf[1] = (2048+2)&0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + } + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((4+2)>>8)&0xff; + buf[1] = (4+2)&0xff; + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048+2)>>8)&0xff; + buf[1] = (2048+2)&0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + buf[6] = ((2048+4)>>8)&0xff; + buf[7] = (2048+4)&0xff; + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + buf[10] = ((4+4)>>8)&0xff; + buf[11] = (4+4)&0xff; + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + buf[14] = ((188+4)>>8)&0xff; + buf[15] = (188+4)&0xff; + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + buf[18] = ((2048+4)>>8)&0xff; + buf[19] = (2048+4)&0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[6] = ((16+2)>>8)&0xff; + buf[7] = (16+2)&0xff; + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + } +} + +static uint32_t atapi_event_status(IDE *ide, uint8_t *buffer) +{ + uint8_t event_code, media_status = 0; + + if (buffer[5]) + { + media_status = MS_TRAY_OPEN; + atapi->stop(); + } + else + { + media_status = MS_MEDIA_PRESENT; + } + + event_code = MEC_NO_CHANGE; + if (media_status != MS_TRAY_OPEN) + { + if (!buffer[4]) + { + event_code = MEC_NEW_MEDIA; + atapi->load(); + } + else if (buffer[4]==2) + { + event_code = MEC_EJECT_REQUESTED; + atapi->eject(); + } + } + + buffer[4] = event_code; + buffer[5] = media_status; + buffer[6] = 0; + buffer[7] = 0; + + return 8; +} + +static int changed_status = 0; + +void atapi_cmd_error(IDE *ide, uint8_t sensekey, uint8_t asc) +{ + ide->error = (sensekey << 4); + ide->atastat = READY_STAT | ERR_STAT; + ide->secount = (ide->secount & ~7) | 3; + ide->packetstatus = 0x80; + idecallback[ide->board]=50*IDE_TIME; +} + +uint8_t atapi_prev; +int toctimes=0; + +void atapi_insert_cdrom() +{ + atapi_sense.sensekey=SENSE_UNIT_ATTENTION; + atapi_sense.asc=ASC_MEDIUM_MAY_HAVE_CHANGED; + atapi_sense.ascq=0; +} + +void atapi_command_send_init(IDE *ide, uint8_t command, int req_length, int alloc_length) +{ + if (ide->cylinder == 0xffff) + ide->cylinder = 0xfffe; + + if ((ide->cylinder & 1) && !(alloc_length <= ide->cylinder)) + { + pclog("Odd byte count (0x%04x) to ATAPI command 0x%02x, using 0x%04x\n", ide->cylinder, command, ide->cylinder - 1); + ide->cylinder--; + } + + if (alloc_length < 0) + fatal("Allocation length < 0\n"); + if (alloc_length == 0) + alloc_length = ide->cylinder; + + // Status: 0x80 (busy), 0x08 (drq), 0x01 (err) + // Interrupt: 0x02 (i_o), 0x01 (c_d) + /* No atastat setting: PCem actually emulates the callback cycle. */ + ide->secount = 2; + + // no bytes transferred yet + ide->pos = 0; + + if ((ide->cylinder > req_length) || (ide->cylinder == 0)) + ide->cylinder = req_length; + if (ide->cylinder > alloc_length) + ide->cylinder = alloc_length; + + //pclog("atapi_command_send_init(ide, %02X, %04X, %04X)\n", command, req_length, alloc_length); + //pclog("IDE settings: Pos=%08X, Secount=%08X, Cylinder=%08X\n", ide->pos, ide->secount, ide->cylinder); +} + +static void atapi_command_ready(int ide_board, int packlen) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + ide->packetstatus = ATAPI_STATUS_REQ_SENSE; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=packlen; +} + +static void atapi_sense_clear(int command, int ignore_ua) +{ + if ((atapi_sense.sensekey == SENSE_UNIT_ATTENTION) || ignore_ua) + { + atapi_prev=command; + atapi_sense.sensekey=0; + atapi_sense.asc=0; + atapi_sense.ascq=0; + } +} + +int cd_status = CD_STATUS_EMPTY; +int prev_status; + +static void atapicommand(int ide_board) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint8_t rcdmode = 0; + int c; + int len; + int msf; + int pos=0; + unsigned char temp; + uint32_t size; + int is_error; + uint8_t page_code; + int max_len; + unsigned idx = 0; + unsigned size_idx; + unsigned preamble_len; + int toc_format; + int temp_command; + int alloc_length; + int completed; + +#ifndef RPCEMU_IDE + pclog("New ATAPI command %02X %i\n",idebufferb[0],ins); +#endif +// readflash=1; + msf=idebufferb[1]&2; + ide->cdlen=0; + + is_error = 0; + + if (atapi->medium_changed()) + { + atapi_insert_cdrom(); + } + /*If UNIT_ATTENTION is set, error out with NOT_READY. + VIDE-CDD.SYS will then issue a READ_TOC, which can pass through UNIT_ATTENTION and will clear sense. + NT 3.1 / AZTIDECD.SYS will then issue a REQUEST_SENSE, which can also pass through UNIT_ATTENTION but will clear sense AFTER sending it back. + In any case, if the command cannot pass through, set our state to errored.*/ + if (!(atapi_cmd_table[idebufferb[0]] & ALLOW_UA) && atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + { + atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + is_error = 1; + } + /*Unless the command issued was a REQUEST_SENSE or TEST_UNIT_READY, clear sense. + This is important because both VIDE-CDD.SYS and NT 3.1 / AZTIDECD.SYS rely on this behaving VERY specifically. + VIDE-CDD.SYS will clear sense through READ_TOC, while NT 3.1 / AZTIDECD.SYS will issue a REQUEST_SENSE.*/ + if ((idebufferb[0]!=GPCMD_REQUEST_SENSE) && (idebufferb[0]!=GPCMD_TEST_UNIT_READY)) + { + /* GPCMD_TEST_UNIT_READY is NOT supposed to clear sense! */ + atapi_sense_clear(idebufferb[0], 1); + } + + /*If our state has been set to errored, clear it, and return.*/ + if (is_error) + { + is_error = 0; + return; + } + + if ((atapi_cmd_table[idebufferb[0]] & CHECK_READY) && !atapi->ready()) + { + atapi_cmd_error(ide, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + atapi_sense.sensekey = SENSE_NOT_READY; + atapi_sense.asc = ASC_MEDIUM_NOT_PRESENT; + atapi_sense.ascq = 0; + return; + } + + prev_status = cd_status; + cd_status = atapi->status(); + if (((prev_status == CD_STATUS_PLAYING) || (prev_status == CD_STATUS_PAUSED)) && ((cd_status != CD_STATUS_PLAYING) && (cd_status != CD_STATUS_PAUSED))) + { + completed = 1; + } + else + { + completed = 0; + } + + switch (idebufferb[0]) + { + case GPCMD_TEST_UNIT_READY: + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_REQUEST_SENSE: /* Used by ROS 4+ */ + alloc_length = idebufferb[4]; + temp_command = idebufferb[0]; + atapi_command_send_init(ide, temp_command, 18, alloc_length); + + /*Will return 18 bytes of 0*/ + memset(idebufferb,0,512); + + idebufferb[0]=0x80|0x70; + + if ((atapi_sense.sensekey > 0) || (cd_status < CD_STATUS_PLAYING)) + { + if (completed) + { + idebufferb[2]=SENSE_ILLEGAL_REQUEST; + idebufferb[12]=ASC_AUDIO_PLAY_OPERATION; + idebufferb[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } + else + { + idebufferb[2]=atapi_sense.sensekey; + idebufferb[12]=atapi_sense.asc; + idebufferb[13]=atapi_sense.ascq; + } + } + else + { + idebufferb[2]=SENSE_ILLEGAL_REQUEST; + idebufferb[12]=ASC_AUDIO_PLAY_OPERATION; + idebufferb[13]=(cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } + + idebufferb[7]=10; + + // pclog("REQUEST SENSE start\n"); + atapi_command_ready(ide_board, 18); + + /* Clear the sense stuff as per the spec. */ + atapi_sense_clear(temp_command, 0); + break; + + case GPCMD_SET_SPEED: + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_MECHANISM_STATUS: /*0xbd*/ + len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; + + if (len == 0) + fatal("Zero allocation length to MECHANISM STATUS not impl.\n"); + + atapi_command_send_init(ide, idebufferb[0], 8, alloc_length); + + idebufferb[0] = 0; + idebufferb[1] = 0; + idebufferb[2] = 0; + idebufferb[3] = 0; + idebufferb[4] = 0; + idebufferb[5] = 1; + idebufferb[6] = 0; + idebufferb[7] = 0; + // len = 8; + + atapi_command_ready(ide_board, 8); + break; + + case GPCMD_READ_TOC_PMA_ATIP: +// pclog("Read TOC ready? %08X\n",ide); + toctimes++; +// if (toctimes==2) output=3; +// pclog("Read TOC %02X\n",idebufferb[9]); + toc_format = idebufferb[2] & 0xf; + if (toc_format == 0) + toc_format = (idebufferb[9]>>6) & 3; + switch (toc_format) + { + case 0: /*Normal*/ + // pclog("ATAPI: READ TOC type requested: Normal\n"); + len=idebufferb[8]+(idebufferb[7]<<8); + len=atapi->readtoc(idebufferb,idebufferb[6],msf,len,0); + break; + case 1: /*Multi session*/ + // pclog("ATAPI: READ TOC type requested: Multi-session\n"); + len=idebufferb[8]+(idebufferb[7]<<8); + len=atapi->readtoc_session(idebufferb,msf,len); + idebufferb[0]=0; idebufferb[1]=0xA; + break; + case 2: /*Raw*/ + // pclog("ATAPI: READ TOC type requested: Raw TOC\n"); + len=idebufferb[8]+(idebufferb[7]<<8); + len=atapi->readtoc_raw(idebufferb,len); + break; + default: + // pclog("ATAPI: Unknown READ TOC type requested: %i\n", (idebufferb[9]>>6)); + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + return; +/* pclog("Bad read TOC format\n"); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X ",idebufferb[c]); + pclog("\n"); + exit(-1);*/ + } +// pclog("ATAPI buffer len %i\n",len); + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=len; + return; + + case GPCMD_READ_CD: +// pclog("Read CD : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); + rcdmode = idebufferb[9] & 0xF8; + if ((rcdmode != 0x10) && (rcdmode != 0xF8)) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; +// pclog("Bad flags bits %02X\n",idebufferb[9]); +// exit(-1); + } +/* if (idebufferb[6] || idebufferb[7] || (idebufferb[8]!=1)) + { + pclog("More than 1 sector!\n"); + exit(-1); + }*/ + ide->cdlen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; + ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; +// pclog("Read at %08X %08X\n",ide.cdpos,ide.cdpos*2048); + if (rcdmode == 0x10) + atapi->readsector(idebufferb,ide->cdpos); + else + atapi->readsector_raw(idebufferb,ide->cdpos); +#ifndef RPCEMU_IDE + readflash=1; +#endif + readcdmode = (rcdmode == 0xF8); + ide->cdpos++; + ide->cdlen--; + if (ide->cdlen >= 0) + ide->packetstatus = ATAPI_STATUS_READCD; + else + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=(idebufferb[9] == 0x10) ? 2048 : 2352; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=(idebufferb[9] == 0x10) ? 2048 : 2352; + return; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: +// pclog("Read 10 : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); + + readcdmode = 0; + + if (idebufferb[0] == GPCMD_READ_6) + { + ide->cdlen=idebufferb[4]; + ide->cdpos=((((uint32_t) idebufferb[1]) & 0x1f)<<16)|(((uint32_t) idebufferb[2])<<8)|((uint32_t) idebufferb[3]); + } + else if (idebufferb[0] == GPCMD_READ_10) + { + ide->cdlen=(idebufferb[7]<<8)|idebufferb[8]; + ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + } + else + { + ide->cdlen=(((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]); + ide->cdpos=(((uint32_t) idebufferb[2])<<24)|(((uint32_t) idebufferb[3])<<16)|(((uint32_t) idebufferb[4])<<8)|((uint32_t) idebufferb[5]); + } + if (!ide->cdlen) + { +// pclog("All done - callback set\n"); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=20*IDE_TIME; + break; + } + + atapi->readsector(idebufferb,ide->cdpos); +#ifndef RPCEMU_IDE + readflash=1; +#endif + ide->cdpos++; + ide->cdlen--; + if (ide->cdlen >= 0) + ide->packetstatus = ATAPI_STATUS_READCD; + else + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=2048; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=2048; + return; + + case GPCMD_READ_HEADER: + if (msf) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + { + ide->error |= MCR_ERR; + } + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; +// pclog("Read Header MSF!\n"); +// exit(-1); + } + for (c=0;c<4;c++) idebufferb[c+4]=idebufferb[c+2]; + idebufferb[0]=1; /*2048 bytes user data*/ + idebufferb[1]=idebufferb[2]=idebufferb[3]=0; + + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=8; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=8; + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + temp_command = idebufferb[0]; + + if (temp_command == GPCMD_MODE_SENSE_6) + len=idebufferb[4]; + else + len=(idebufferb[8]|(idebufferb[7]<<8)); + + temp=idebufferb[2] & 0x3F; + + memset(idebufferb, 0, len); + alloc_length = len; + // for (c=0;catastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + idecallback[ide_board]=50*IDE_TIME; + atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + ide->atastat = 0x53; + ide->packetstatus = ATAPI_STATUS_ERROR; + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + atapi_sense.ascq = 0; + return; + } + + if (temp_command == GPCMD_MODE_SENSE_6) + { + len = ide_atapi_mode_sense(ide,4,temp); + idebufferb[0] = len - 1; + idebufferb[1]=3; /*120mm data CD-ROM*/ + } + else + { + len = ide_atapi_mode_sense(ide,8,temp); + idebufferb[0]=(len - 2)>>8; + idebufferb[1]=(len - 2)&255; + idebufferb[2]=3; /*120mm data CD-ROM*/ + } + + atapi_command_send_init(ide, temp_command, len, alloc_length); + + atapi_command_ready(ide_board, len); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) + { + ide->atastat = READY_STAT; + ide->secount=3; +// pclog("Recieve data packet!\n"); + ide_irq_raise(ide); + ide->packetstatus=0xFF; + ide->pos=0; + // pclog("Length - %02X%02X\n",idebufferb[0],idebufferb[1]); +// pclog("Page %02X length %02X\n",idebufferb[8],idebufferb[9]); + } + else + { + if (idebufferb[0] == GPCMD_MODE_SELECT_6) + { + len=idebufferb[4]; + prefix_len = 6; + } + else + { + len=(idebufferb[7]<<8)|idebufferb[8]; + prefix_len = 10; + } + page_current = idebufferb[2]; + if (page_flags[page_current] & PAGE_CHANGEABLE) + page_flags[GPMODE_CDROM_AUDIO_PAGE] |= PAGE_CHANGED; + ide->packetstatus = ATAPI_STATUS_PACKET_REQ; + ide->cylinder=len; + ide->secount=0; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=len; +/* pclog("Waiting for ARM to send packet %i\n",len); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X ",idebufferb[c]); + pclog("\n");*/ + } + return; + + case GPCMD_GET_CONFIGURATION: + { + temp_command = idebufferb[0]; + /* XXX: could result in alignment problems in some architectures */ + len = (idebufferb[7]<<8)|idebufferb[8]; + alloc_length = len; + + uint8_t index = 0; + + /* only feature 0 is supported */ + if (idebufferb[2] != 0 || idebufferb[3] != 0) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + return; + } + + /* + * XXX: avoid overflow for io_buffer if len is bigger than + * the size of that buffer (dimensioned to max number of + * sectors to transfer at once) + * + * Only a problem if the feature/profiles grow. + */ + if (alloc_length > 512) /* XXX: assume 1 sector */ + alloc_length = 512; + + memset(idebufferb, 0, alloc_length); + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (len > CD_MAX_SECTORS ) + { + idebufferb[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + idebufferb[7] = MMC_PROFILE_DVD_ROM & 0xff; + } + else if (len <= CD_MAX_SECTORS) + { + idebufferb[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + idebufferb[7] = MMC_PROFILE_CD_ROM & 0xff; + } + idebufferb[10] = 0x02 | 0x01; /* persistent and current */ + alloc_length = 12; /* headers: 8 + 4 */ + alloc_length += atapi_set_profile(idebufferb, &index, MMC_PROFILE_DVD_ROM); + alloc_length += atapi_set_profile(idebufferb, &index, MMC_PROFILE_CD_ROM); + idebufferb[0] = ((alloc_length-4) >> 24) & 0xff; + idebufferb[1] = ((alloc_length-4) >> 16) & 0xff; + idebufferb[2] = ((alloc_length-4) >> 8) & 0xff; + idebufferb[3] = (alloc_length-4) & 0xff; + + atapi_command_send_init(ide, temp_command, len, alloc_length); + + atapi_command_ready(ide_board, len); + } + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: /*0x4a*/ + temp_command = idebufferb[0]; + alloc_length = len; + + { + struct + { + uint8_t opcode; + uint8_t polled; + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; + } *gesn_cdb; + + struct + { + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; + } *gesn_event_header; + unsigned int used_len; + + gesn_cdb = (void *)idebufferb; + gesn_event_header = (void *)idebufferb; + + /* It is fine by the MMC spec to not support async mode operations */ + if (!(gesn_cdb->polled & 0x01)) + { /* asynchronous mode */ + /* Only pollign is supported, asynchronous mode is not. */ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + idecallback[ide_board]=50*IDE_TIME; + atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + ide->atastat = 0x53; + ide->packetstatus=0x80; + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + atapi_sense.ascq = 0; + return; + } + + /* polling mode operation */ + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + * Notification class requests and supported event classes are bitmasks, + * but they are built from the same values as the "notification class" + * field. + */ + gesn_event_header->supported_events = 1 << GESN_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & (1 << GESN_MEDIA)) + { + gesn_event_header->notification_class |= GESN_MEDIA; + used_len = atapi_event_status(ide, idebufferb); + } + else + { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + } + + atapi_command_send_init(ide, temp_command, len, alloc_length); + + atapi_command_ready(ide_board, len); + break; + + case GPCMD_READ_DISC_INFORMATION: + idebufferb[1] = 32; + idebufferb[2] = 0xe; /* last session complete, disc finalized */ + idebufferb[3] = 1; /* first track on disc */ + idebufferb[4] = 1; /* # of sessions */ + idebufferb[5] = 1; /* first track of last session */ + idebufferb[6] = 1; /* last track of last session */ + idebufferb[7] = 0x20; /* unrestricted use */ + idebufferb[8] = 0x00; /* CD-ROM */ + + len=34; + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=len; + break; + + case GPCMD_PLAY_AUDIO_10: + case GPCMD_PLAY_AUDIO_12: + case GPCMD_PLAY_AUDIO_MSF: + /*This is apparently deprecated in the ATAPI spec, and apparently + has been since 1995 (!). Hence I'm having to guess most of it*/ + if (idebufferb[0] == GPCMD_PLAY_AUDIO_10) + { + pos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + len=(idebufferb[7]<<8)|idebufferb[8]; + } + else if (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) + { + pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + len=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; + } + else + { + pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; + } + + + if ((cdrom_drive < 1) || (cdrom_drive == CDROM_ISO) || (cd_status <= CD_STATUS_DATA_ONLY) || + !atapi->is_track_audio(pos, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + atapi_sense.ascq = 0; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + break; + } + + atapi->playaudio(pos, len, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_READ_SUBCHANNEL: + temp=idebufferb[2]&0x40; + if (idebufferb[3]!=1) + { +// pclog("Read subchannel check condition %02X\n",idebufferb[3]); + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + // ide->discchanged=1; /* Fixes some bugs with NT 3.1. */ + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; +/* pclog("Bad read subchannel!\n"); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X\n",idebufferb[c]); + dumpregs(); + exit(-1);*/ + } + pos=0; + idebufferb[pos++]=0; + idebufferb[pos++]=0; /*Audio status*/ + idebufferb[pos++]=0; idebufferb[pos++]=0; /*Subchannel length*/ + idebufferb[pos++]=1; /*Format code*/ + idebufferb[1]=atapi->getcurrentsubchannel(&idebufferb[5],msf); +// pclog("Read subchannel complete - audio status %02X\n",idebufferb[1]); + len=11+5; + if (!temp) len=4; + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=1000*IDE_TIME; + ide->packlen=len; + break; + + case GPCMD_READ_DVD_STRUCTURE: + temp_command = idebufferb[0]; + int media = idebufferb[1]; + int format = idebufferb[7]; + int ret; + + len = (((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]); + alloc_length = len; + + if (format < 0xff) { + if (len <= CD_MAX_SECTORS) { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + atapi_sense.asc = ASC_INCOMPATIBLE_FORMAT; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; + } else { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + return; + } + } + + memset(idebufferb, 0, alloc_length > 256 * 512 + 4 ? + 256 * 512 + 4 : alloc_length); + + switch (format) { + case 0x00 ... 0x7f: + case 0xff: + if (media == 0) { + ret = atapi_read_structure(ide, format, idebufferb, idebufferb); + + if (ret < 0) + atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, -ret); + else + { + atapi_command_send_init(ide, temp_command, len, alloc_length); + atapi_command_ready(ide_board, len); + } + break; + } + /* TODO: BD support, fall through for now */ + + /* Generic disk structures */ + case 0x80: /* TODO: AACS volume identifier */ + case 0x81: /* TODO: AACS media serial number */ + case 0x82: /* TODO: AACS media identifier */ + case 0x83: /* TODO: AACS media key block */ + case 0x90: /* TODO: List of recognized format layers */ + case 0xc0: /* TODO: Write protection status */ + default: + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + return; + } + break; + + case GPCMD_START_STOP_UNIT: + if (idebufferb[4]!=2 && idebufferb[4]!=3 && idebufferb[4]) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; +/* pclog("Bad start/stop unit command\n"); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X\n",idebufferb[c]); + exit(-1);*/ + } + if (!idebufferb[4]) atapi->stop(); + else if (idebufferb[4]==2) atapi->eject(); + else atapi->load(); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_INQUIRY: + page_code = idebufferb[2]; + max_len = idebufferb[4]; + alloc_length = max_len; + temp_command = idebufferb[0]; + + if (idebufferb[1] & 1) + { + preamble_len = 4; + size_idx = 3; + + idebufferb[idx++] = 05; + idebufferb[idx++] = page_code; + idebufferb[idx++] = 0; + + idx++; + + switch (page_code) + { + case 0x00: + idebufferb[idx++] = 0x00; + idebufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) + { + atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR); + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_DATA_PHASE_ERROR; + return; + } + idebufferb[idx++] = 0x02; + idebufferb[idx++] = 0x00; + idebufferb[idx++] = 0x00; + idebufferb[idx++] = 20; + ide_padstr8(idebufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > max_len) + { + goto atapi_out; + } + idebufferb[idx++] = 0x02; + idebufferb[idx++] = 0x01; + idebufferb[idx++] = 0x00; + idebufferb[idx++] = 68; + ide_padstr8(idebufferb + idx, 8, "PCem"); /* Vendor */ + idx += 8; + ide_padstr8(idebufferb + idx, 40, "PCemCD v1.0"); /* Product */ + idx += 40; + ide_padstr8(idebufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + + break; + default: + atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + return; + } + } + else + { + preamble_len = 5; + size_idx = 4; + + idebufferb[0] = 5; /*CD-ROM*/ + idebufferb[1] = 0x80; /*Removable*/ + idebufferb[2] = 0; + idebufferb[3] = 0x21; + idebufferb[4] = 31; + idebufferb[5] = 0; + idebufferb[6] = 0; + idebufferb[7] = 0; +#ifdef RPCEMU_IDE + ide_padstr8(idebufferb + 8, 8, "RPCemu"); /* Vendor */ + ide_padstr8(idebufferb + 16, 16, "RPCemuCD"); /* Product */ +#else + ide_padstr8(idebufferb + 8, 8, "PCem"); /* Vendor */ + ide_padstr8(idebufferb + 16, 16, "PCemCD"); /* Product */ +#endif + ide_padstr8(idebufferb + 32, 4, "1.0"); /* Revision */ + + idx = 36; + } + +atapi_out: + idebufferb[size_idx] = idx - preamble_len; + len=idx; + + atapi_command_send_init(ide, temp_command, len, alloc_length); + + atapi_command_ready(ide_board, len); + break; + + case GPCMD_PREVENT_REMOVAL: + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_PAUSE_RESUME: + if (idebufferb[8]&1) atapi->resume(); + else atapi->pause(); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_SEEK: + pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + atapi->seek(pos); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_READ_CDROM_CAPACITY: + atapi_command_send_init(ide, temp_command, 8, 8); + size = atapi->size(); + idebufferb[0] = (size >> 24) & 0xff; + idebufferb[1] = (size >> 16) & 0xff; + idebufferb[2] = (size >> 8) & 0xff; + idebufferb[3] = size & 0xff; + idebufferb[4] = (2048 >> 24) & 0xff; + idebufferb[5] = (2048 >> 16) & 0xff; + idebufferb[6] = (2048 >> 8) & 0xff; + idebufferb[7] = 2048 & 0xff; + len=8; + atapi_command_ready(ide_board, len); + break; + + case GPCMD_SEND_DVD_STRUCTURE: + default: +bad_atapi_command: + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_STOP_PLAY_SCAN: + atapi->stop(); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; +/* default: + pclog("Bad ATAPI command %02X\n",idebufferb[0]); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X\n",idebufferb[c]); + exit(-1);*/ + } +} + +static void callnonreadcd(IDE *ide) /* Callabck for non-Read CD commands */ +{ + ide_irq_lower(ide); + if (ide->pos >= ide->packlen) + { + // pclog("Command finished, setting callback\n"); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide->board]=20*IDE_TIME; + } + else + { + // pclog("Command not finished, keep sending data\n"); + ide->atastat = BUSY_STAT; + ide->packetstatus = ATAPI_STATUS_REQ_SENSE; + ide->cylinder=2; + ide->secount=2; + idecallback[ide->board]=60*IDE_TIME; + } +} + +static void callreadcd(IDE *ide) +{ + ide_irq_lower(ide); + if (ide->cdlen<=0) + { +// pclog("All done - callback set\n"); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide->board]=20*IDE_TIME; + return; + } +// pclog("Continue readcd! %i blocks left\n",ide->cdlen); + ide->atastat = BUSY_STAT; + + if (readcdmode) + atapi->readsector_raw((uint8_t *) ide->buffer, ide->cdpos); + else + atapi->readsector((uint8_t *) ide->buffer, ide->cdpos); +#ifndef RPCEMU_IDE + readflash=1; +#endif + ide->cdpos++; + ide->cdlen--; + ide->packetstatus = ATAPI_STATUS_READCD; + ide->cylinder=readcdmode ? 2352 : 2048; + ide->secount=2; + ide->pos=0; + idecallback[ide->board]=60*IDE_TIME; + ide->packlen=readcdmode ? 2352 : 2048; +} + + + +void ide_write_pri(uint16_t addr, uint8_t val, void *priv) +{ + writeide(0, addr, val); +} +void ide_write_pri_w(uint16_t addr, uint16_t val, void *priv) +{ + writeidew(0, val); +} +void ide_write_pri_l(uint16_t addr, uint32_t val, void *priv) +{ + writeidel(0, val); +} +uint8_t ide_read_pri(uint16_t addr, void *priv) +{ + return readide(0, addr); +} +uint16_t ide_read_pri_w(uint16_t addr, void *priv) +{ + return readidew(0); +} +uint32_t ide_read_pri_l(uint16_t addr, void *priv) +{ + return readidel(0); +} + +void ide_write_sec(uint16_t addr, uint8_t val, void *priv) +{ + writeide(1, addr, val); +} +void ide_write_sec_w(uint16_t addr, uint16_t val, void *priv) +{ + writeidew(1, val); +} +void ide_write_sec_l(uint16_t addr, uint32_t val, void *priv) +{ + writeidel(1, val); +} +uint8_t ide_read_sec(uint16_t addr, void *priv) +{ + return readide(1, addr); +} +uint16_t ide_read_sec_w(uint16_t addr, void *priv) +{ + return readidew(1); +} +uint32_t ide_read_sec_l(uint16_t addr, void *priv) +{ + return readidel(1); +} + +/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - START *** */ +void ide_write_ter(uint16_t addr, uint8_t val, void *priv) +{ + writeide(2, addr, val); +} +void ide_write_ter_w(uint16_t addr, uint16_t val, void *priv) +{ + writeidew(2, val); +} +void ide_write_ter_l(uint16_t addr, uint32_t val, void *priv) +{ + writeidel(2, val); +} +uint8_t ide_read_ter(uint16_t addr, void *priv) +{ + return readide(2, addr); +} +uint16_t ide_read_ter_w(uint16_t addr, void *priv) +{ + return readidew(2); +} +uint32_t ide_read_ter_l(uint16_t addr, void *priv) +{ + return readidel(2); +} +/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - END *** */ + +void ide_pri_enable() +{ + io_sethandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); + io_sethandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); +} + +void ide_pri_disable() +{ + io_removehandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); + io_removehandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); +} + +void ide_sec_enable() +{ + io_sethandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); + io_sethandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); +} + +void ide_sec_disable() +{ + io_removehandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); + io_removehandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); +} + +/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - START *** */ +void ide_ter_enable() +{ + io_sethandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); + io_sethandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); +} + +void ide_ter_disable() +{ + io_removehandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); + io_removehandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); +} + +void ide_ter_init() +{ + ide_ter_enable(); + + timer_add(ide_callback_ter, &idecallback[2], &idecallback[2], NULL); +} +/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - END *** */ + +void ide_init() +{ + ide_pri_enable(); + ide_sec_enable(); + ide_bus_master_read_sector = ide_bus_master_write_sector = NULL; + + timer_add(ide_callback_pri, &idecallback[0], &idecallback[0], NULL); + timer_add(ide_callback_sec, &idecallback[1], &idecallback[1], NULL); +} + +void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel)) +{ + ide_bus_master_read_sector = read_sector; + ide_bus_master_write_sector = write_sector; + ide_bus_master_set_irq = set_irq; +} diff --git a/src/ide.h b/src/ide.h new file mode 100644 index 000000000..f4861a232 --- /dev/null +++ b/src/ide.h @@ -0,0 +1,60 @@ +#ifndef __IDE__ +#define __IDE__ + +struct IDE; + +extern void writeide(int ide_board, uint16_t addr, uint8_t val); +extern void writeidew(int ide_board, uint16_t val); +extern uint8_t readide(int ide_board, uint16_t addr); +extern uint16_t readidew(int ide_board); +extern void callbackide(int ide_board); +extern void resetide(void); +extern void ide_init(); +extern void ide_ter_init(); +extern void ide_pri_enable(); +extern void ide_sec_enable(); +extern void ide_ter_enable(); +extern void ide_pri_disable(); +extern void ide_sec_disable(); +extern void ide_ter_disable(); +extern void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel)); + +/*ATAPI stuff*/ +typedef struct ATAPI +{ + int (*ready)(void); + int (*medium_changed)(void); + int (*readtoc)(uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); + int (*readtoc_session)(uint8_t *b, int msf, int maxlen); + int (*readtoc_raw)(uint8_t *b, int maxlen); + uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf); + void (*readsector)(uint8_t *b, int sector); + void (*readsector_raw)(uint8_t *b, int sector); + void (*playaudio)(uint32_t pos, uint32_t len, int ismsf); + void (*seek)(uint32_t pos); + void (*load)(void); + void (*eject)(void); + void (*pause)(void); + void (*resume)(void); + uint32_t (*size)(void); + int (*status)(void); + int (*is_track_audio)(uint32_t pos, int ismsf); + void (*stop)(void); + void (*exit)(void); +} ATAPI; + +extern ATAPI *atapi; + +void atapi_discchanged(); + +void atapi_insert_cdrom(); + +extern int ideboard; + +extern int idecallback[3]; + +extern char ide_fn[4][512]; + +extern int cdrom_channel; + +#endif //__IDE__ diff --git a/src/intel.c b/src/intel.c new file mode 100644 index 000000000..5b96fca6f --- /dev/null +++ b/src/intel.c @@ -0,0 +1,81 @@ +#include "ibm.h" +#include "cpu.h" +#include "io.h" +#include "mem.h" +#include "pit.h" +#include "timer.h" + +#include "intel.h" + +uint8_t batman_brdconfig(uint16_t port, void *p) +{ +// pclog("batman_brdconfig read port=%04x\n", port); + switch (port) + { + case 0x73: + return 0xff; + case 0x75: + return 0xdf; + } + return 0; +} + +static uint16_t batman_timer_latch; +static int batman_timer = 0; +static void batman_timer_over(void *p) +{ + batman_timer = 0; +} + +static void batman_timer_write(uint16_t addr, uint8_t val, void *p) +{ + if (addr & 1) + batman_timer_latch = (batman_timer_latch & 0xff) | (val << 8); + else + batman_timer_latch = (batman_timer_latch & 0xff00) | val; + batman_timer = batman_timer_latch * TIMER_USEC; +} + +static uint8_t batman_timer_read(uint16_t addr, void *p) +{ + uint16_t batman_timer_latch; + + cycles -= (int)PITCONST; + + timer_clock(); + + if (batman_timer < 0) + return 0; + + batman_timer_latch = batman_timer / TIMER_USEC; + + if (addr & 1) + return batman_timer_latch >> 8; + return batman_timer_latch & 0xff; +} + +void intel_batman_init() +{ + io_sethandler(0x0073, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); + io_sethandler(0x0075, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); + + io_sethandler(0x0078, 0x0002, batman_timer_read, NULL, NULL, batman_timer_write, NULL, NULL, NULL); + timer_add(batman_timer_over, &batman_timer, &batman_timer, NULL); +} + + +uint8_t endeavor_brdconfig(uint16_t port, void *p) +{ +// pclog("endeavor_brdconfig read port=%04x\n", port); + switch (port) + { + case 0x79: + return 0xff; + } + return 0; +} + +void intel_endeavor_init() +{ + io_sethandler(0x0079, 0x0001, endeavor_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); +} diff --git a/src/intel.h b/src/intel.h new file mode 100644 index 000000000..9032cca83 --- /dev/null +++ b/src/intel.h @@ -0,0 +1,2 @@ +void intel_batman_init(); +void intel_endeavor_init(); diff --git a/src/intel_flash.c b/src/intel_flash.c new file mode 100644 index 000000000..e3434ae1c --- /dev/null +++ b/src/intel_flash.c @@ -0,0 +1,419 @@ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" + +enum +{ + CMD_READ_ARRAY = 0xff, + CMD_IID = 0x90, + CMD_READ_STATUS = 0x70, + CMD_CLEAR_STATUS = 0x50, + CMD_ERASE_SETUP = 0x20, + CMD_ERASE_CONFIRM = 0xd0, + CMD_ERASE_SUSPEND = 0xb0, + CMD_PROGRAM_SETUP = 0x40 +}; + +typedef struct flash_t +{ + uint32_t command, status; + uint32_t data_addr1, data_addr2, data_start, boot_start; + uint32_t main_start[2], main_end[2], main_len[2]; + uint32_t flash_id, invert_high_pin; + mem_mapping_t read_mapping, write_mapping; + mem_mapping_t read_mapping_h, write_mapping_h; +} flash_t; + +static flash_t flash; + +char flash_path[1024]; + +#if 0 +mem_mapping_t flash_null_mapping[4]; + +uint8_t flash_read_null(uint32_t addr, void *priv) +{ + return 0xff; +} + +uint16_t flash_read_nullw(uint32_t addr, void *priv) +{ + return 0xffff; +} + +uint32_t flash_read_nulll(uint32_t addr, void *priv) +{ +// pclog("Read BIOS %08X %02X %04X:%04X\n", addr, *(uint32_t *)&rom[addr & biosmask], CS, pc); + return 0xffffffff; +} + +void flash_null_mapping_disable() +{ + mem_mapping_disable(&flash_null_mapping[0]); + mem_mapping_disable(&flash_null_mapping[1]); + mem_mapping_disable(&flash_null_mapping[2]); + mem_mapping_disable(&flash_null_mapping[3]); +} + +void flash_null_mapping_enable() +{ + mem_mapping_enable(&flash_null_mapping[0]); + mem_mapping_enable(&flash_null_mapping[1]); + mem_mapping_enable(&flash_null_mapping[2]); + mem_mapping_enable(&flash_null_mapping[3]); +} + +void flash_add_null_mapping() +{ + mem_mapping_add(&flash_null_mapping[0], 0xe0000, 0x04000, flash_read_null, flash_read_nullw, flash_read_nulll, mem_write_null, mem_write_nullw, mem_write_nulll, NULL, MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&flash_null_mapping[1], 0xe4000, 0x04000, flash_read_null, flash_read_nullw, flash_read_nulll, mem_write_null, mem_write_nullw, mem_write_nulll, NULL, MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&flash_null_mapping[2], 0xe8000, 0x04000, flash_read_null, flash_read_nullw, flash_read_nulll, mem_write_null, mem_write_nullw, mem_write_nulll, NULL, MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&flash_null_mapping[3], 0xec000, 0x04000, flash_read_null, flash_read_nullw, flash_read_nulll, mem_write_null, mem_write_nullw, mem_write_nulll, NULL, MEM_MAPPING_EXTERNAL, 0); + + flash_null_mapping_disable(); +} +#endif + +static uint8_t flash_read(uint32_t addr, void *p) +{ + flash_t *flash = (flash_t *)p; + // pclog("flash_read : addr=%08x command=%02x %04x:%08x\n", addr, flash->command, CS, pc); + switch (flash->command) + { + case CMD_IID: + if (addr & 1) + return flash->flash_id; + return 0x89; + + default: + return flash->status; + } +} + +static void flash_write(uint32_t addr, uint8_t val, void *p) +{ + flash_t *flash = (flash_t *)p; + int i; + // pclog("flash_write : addr=%08x val=%02x command=%02x %04x:%08x\n", addr, val, flash->command, CS, pc); + switch (flash->command) + { + case CMD_ERASE_SETUP: + if (val == CMD_ERASE_CONFIRM) + { + // pclog("flash_write: erase %05x\n", addr & 0x1ffff); + + if ((addr & 0x1f000) == flash->data_addr1) + memset(&rom[flash->data_addr1], 0xff, 0x1000); + if ((addr & 0x1f000) == flash->data_addr2) + memset(&rom[flash->data_addr2], 0xff, 0x1000); + if (((addr & 0x1ffff) >= flash->main_start[0]) && ((addr & 0x1ffff) <= flash->main_end[0]) && flash->main_len[0]) + memset(&rom[flash->main_start[0]], 0xff, flash->main_len[0]); + if (((addr & 0x1ffff) >= flash->main_start[1]) && ((addr & 0x1ffff) <= flash->main_end[1]) && flash->main_len[1]) + memset(&rom[flash->main_start[1]], 0xff, flash->main_len[1]); + + flash->status = 0x80; + } + flash->command = CMD_READ_STATUS; + break; + + case CMD_PROGRAM_SETUP: + // pclog("flash_write: program %05x %02x\n", addr & 0x1ffff, val); + if ((addr & 0x1e000) != (flash->boot_start & 0x1e000)) + rom[addr & 0x1ffff] = val; + flash->command = CMD_READ_STATUS; + flash->status = 0x80; + break; + + default: + flash->command = val; + switch (val) + { + case CMD_CLEAR_STATUS: + flash->status = 0; + break; + + case CMD_IID: + case CMD_READ_STATUS: + for (i = 0; i < 8; i++) + { + mem_mapping_disable((addr & 0x8000000) ? &bios_high_mapping[i] : &bios_mapping[i]); + } + mem_mapping_enable((addr & 0x8000000) ? &flash->read_mapping_h : &flash->read_mapping); + break; + + case CMD_READ_ARRAY: + for (i = 0; i < 8; i++) + { + mem_mapping_enable((addr & 0x8000000) ? &bios_high_mapping[i] : &bios_mapping[i]); + } + mem_mapping_disable((addr & 0x8000000) ? &flash->read_mapping_h : &flash->read_mapping); +#if 0 + if ((romset == ROM_MB500N) || (romset == ROM_430VX) || (romset == ROM_P55VA) || (romset == ROM_P55TVP4) || (romset == ROM_440FX)) + { + for (i = 0; i < 4; i++) + { + mem_mapping_disable(&bios_mapping[i]); + } + + flash_null_mapping_enable(); + } + pclog("; This line needed\n"); +#endif + break; + } + } +} + +void *intel_flash_init(int type) +{ + FILE *f; + flash_t *flash = malloc(sizeof(flash_t)); + char fpath[1024]; + memset(flash, 0, sizeof(flash_t)); + + // pclog("Initializing Flash (type = %i)\n", type); + + memset(flash_path, 0, 1024); + + switch(romset) + { + case ROM_REVENGE: + strcpy(flash_path, "roms/revenge/"); + break; + case ROM_586MC1: + strcpy(flash_path, "roms/586mc1/"); + break; + case ROM_PLATO: + strcpy(flash_path, "roms/plato/"); + break; + case ROM_ENDEAVOR: + strcpy(flash_path, "roms/endeavor/"); + break; + case ROM_MB500N: + strcpy(flash_path, "roms/mb500n/"); + break; + case ROM_P54TP4XE: + strcpy(flash_path, "roms/p54tp4xe/"); + break; + case ROM_ACERM3A: + strcpy(flash_path, "roms/acerm3a/"); + break; + case ROM_ACERV35N: + strcpy(flash_path, "roms/acerv35n/"); + break; + case ROM_P55TVP4: + strcpy(flash_path, "roms/p55tvp4/"); + break; + case ROM_P55T2P4: + strcpy(flash_path, "roms/p55t2p4/"); + break; + case ROM_430VX: + strcpy(flash_path, "roms/430vx/"); + break; + case ROM_P55VA: + strcpy(flash_path, "roms/p55va/"); + break; + case ROM_440FX: + strcpy(flash_path, "roms/440fx/"); + break; + case ROM_KN97: + strcpy(flash_path, "roms/kn97/"); + break; + } + // pclog("Flash init: Path is: %s\n", flash_path); + + switch(type) + { + case 0: + flash->data_addr1 = 0xc000; + flash->data_addr2 = 0xd000; + flash->data_start = 0xc000; + flash->boot_start = 0xe000; + flash->main_start[0] = 0x0000; + flash->main_end[0] = 0xbfff; + flash->main_len[0] = 0xc000; + flash->main_start[1] = 0x10000; + flash->main_end[1] = 0x1ffff; + flash->main_len[1] = 0x10000; + break; + case 1: + flash->data_addr1 = 0x1c000; + flash->data_addr2 = 0x1d000; + flash->data_start = 0x1c000; + flash->boot_start = 0x1e000; + flash->main_start[0] = 0x00000; + flash->main_end[0] = 0x1bfff; + flash->main_len[0] = 0x1c000; + flash->main_start[1] = flash->main_end[1] = flash->main_len[1] = 0; + break; + case 2: + flash->data_addr1 = 0x3000; + flash->data_addr2 = 0x2000; + flash->data_start = 0x2000; + flash->boot_start = 0x00000; + flash->main_start[0] = 0x04000; + flash->main_end[0] = 0x1ffff; + flash->main_len[0] = 0x1c000; + flash->main_start[1] = flash->main_end[1] = flash->main_len[1] = 0; + break; + } + + flash->flash_id = (type != 2) ? 0x94 : 0x95; + flash->invert_high_pin = (type == 0) ? 1 : 0; + + mem_mapping_add(&flash->read_mapping, + 0xe0000, + 0x20000, + flash_read, NULL, NULL, + NULL, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, (void *)flash); + mem_mapping_add(&flash->write_mapping, + 0xe0000, + 0x20000, + NULL, NULL, NULL, + flash_write, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, (void *)flash); + mem_mapping_disable(&flash->read_mapping); + if (type > 0) + { + mem_mapping_add(&flash->read_mapping_h, + 0xfffe0000, + 0x20000, + flash_read, NULL, NULL, + NULL, NULL, NULL, + NULL, 0, (void *)flash); + mem_mapping_add(&flash->write_mapping_h, + 0xfffe0000, + 0x20000, + NULL, NULL, NULL, + flash_write, NULL, NULL, + NULL, 0, (void *)flash); + mem_mapping_disable(&flash->read_mapping_h); + /* if (romset != ROM_P55TVP4) */ mem_mapping_disable(&flash->write_mapping); + } + flash->command = CMD_READ_ARRAY; + flash->status = 0; + + if ((romset == ROM_586MC1) || (romset == ROM_MB500N) || (type == 0)) + { + memset(&rom[flash->data_addr2], 0xFF, 0x1000); + } + else + { + memset(&rom[flash->data_start], 0xFF, 0x2000); + } + + if ((romset != ROM_586MC1) && (romset != ROM_MB500N) && (type > 0)) + { + memset(fpath, 0, 1024); + strcpy(fpath, flash_path); + strcat(fpath, "dmi.bin"); + f = romfopen(fpath, "rb"); + if (f) + { + fread(&rom[flash->data_addr1], 0x1000, 1, f); + fclose(f); + } + } + memset(fpath, 0, 1024); + strcpy(fpath, flash_path); + strcat(fpath, "escd.bin"); + f = romfopen(fpath, "rb"); + if (f) + { + fread(&rom[flash->data_addr2], 0x1000, 1, f); + fclose(f); + } + +#if 0 + flash_add_null_mapping(); +#endif + + return flash; +} + +/* For AMI BIOS'es - Intel 28F001BXT with high address pin inverted. */ +void *intel_flash_bxt_ami_init() +{ + return intel_flash_init(0); +} + +/* For Award BIOS'es - Intel 28F001BXT with high address pin not inverted. */ +void *intel_flash_bxt_init() +{ + return intel_flash_init(1); +} + +/* For Acerd BIOS'es - Intel 28F001BXB. */ +void *intel_flash_bxb_init() +{ + return intel_flash_init(2); +} + +void intel_flash_close(void *p) +{ + FILE *f; + flash_t *flash = (flash_t *)p; + + char fpath[1024]; + + // pclog("Flash close: Path is: %s\n", flash_path); + + if ((romset != ROM_586MC1) && (romset != ROM_MB500N)) + { + memset(fpath, 0, 1024); + strcpy(fpath, flash_path); + strcat(fpath, "dmi.bin"); + f = romfopen(fpath, "wb"); + fwrite(&rom[flash->data_addr1], 0x1000, 1, f); + fclose(f); + } + memset(fpath, 0, 1024); + strcpy(fpath, flash_path); + strcat(fpath, "escd.bin"); + f = romfopen(fpath, "wb"); + fwrite(&rom[flash->data_addr2], 0x1000, 1, f); + fclose(f); + + free(flash); +} + +device_t intel_flash_bxt_ami_device = +{ + "Intel 28F001BXT Flash BIOS", + 0, + intel_flash_bxt_ami_init, + intel_flash_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +device_t intel_flash_bxt_device = +{ + "Intel 28F001BXT Flash BIOS", + 0, + intel_flash_bxt_init, + intel_flash_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +device_t intel_flash_bxb_device = +{ + "Intel 28F001BXT Flash BIOS", + 0, + intel_flash_bxb_init, + intel_flash_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/intel_flash.h b/src/intel_flash.h new file mode 100644 index 000000000..e8e0c1bc7 --- /dev/null +++ b/src/intel_flash.h @@ -0,0 +1,3 @@ +extern device_t intel_flash_bxt_ami_device; +extern device_t intel_flash_bxt_device; +extern device_t intel_flash_bxb_device; diff --git a/src/io.c b/src/io.c new file mode 100644 index 000000000..53a2ddbbf --- /dev/null +++ b/src/io.c @@ -0,0 +1,202 @@ +#include "ibm.h" +#include "ide.h" +#include "io.h" +#include "video.h" +#include "cpu.h" + +uint8_t (*port_inb[0x10000][2])(uint16_t addr, void *priv); +uint16_t (*port_inw[0x10000][2])(uint16_t addr, void *priv); +uint32_t (*port_inl[0x10000][2])(uint16_t addr, void *priv); + +void (*port_outb[0x10000][2])(uint16_t addr, uint8_t val, void *priv); +void (*port_outw[0x10000][2])(uint16_t addr, uint16_t val, void *priv); +void (*port_outl[0x10000][2])(uint16_t addr, uint32_t val, void *priv); + +void *port_priv[0x10000][2]; + +void io_init() +{ + int c; + pclog("io_init\n"); + for (c = 0; c < 0x10000; c++) + { + port_inb[c][0] = port_inw[c][0] = port_inl[c][0] = NULL; + port_outb[c][0] = port_outw[c][0] = port_outl[c][0] = NULL; + port_inb[c][1] = port_inw[c][1] = port_inl[c][1] = NULL; + port_outb[c][1] = port_outw[c][1] = port_outl[c][1] = NULL; + port_priv[c][0] = port_priv[c][1] = NULL; + } +} + +void io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + int c; + for (c = 0; c < size; c++) + { + if (!port_inb[ base + c][0] && !port_inw[ base + c][0] && !port_inl[ base + c][0] && + !port_outb[base + c][0] && !port_outw[base + c][0] && !port_outl[base + c][0]) + { + port_inb[ base + c][0] = inb; + port_inw[ base + c][0] = inw; + port_inl[ base + c][0] = inl; + port_outb[base + c][0] = outb; + port_outw[base + c][0] = outw; + port_outl[base + c][0] = outl; + port_priv[base + c][0] = priv; + } + else if (!port_inb[ base + c][1] && !port_inw[ base + c][1] && !port_inl[ base + c][1] && + !port_outb[base + c][1] && !port_outw[base + c][1] && !port_outl[base + c][1]) + { + port_inb[ base + c][1] = inb; + port_inw[ base + c][1] = inw; + port_inl[ base + c][1] = inl; + port_outb[base + c][1] = outb; + port_outw[base + c][1] = outw; + port_outl[base + c][1] = outl; + port_priv[base + c][1] = priv; + } + } +} + +void io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + int c; + for (c = 0; c < size; c++) + { + if (port_priv[base + c][0] == priv) + { + if (port_inb[ base + c][0] == inb) + port_inb[ base + c][0] = NULL; + if (port_inw[ base + c][0] == inw) + port_inw[ base + c][0] = NULL; + if (port_inl[ base + c][0] == inl) + port_inl[ base + c][0] = NULL; + if (port_outb[ base + c][0] == outb) + port_outb[ base + c][0] = NULL; + if (port_outw[ base + c][0] == outw) + port_outw[ base + c][0] = NULL; + if (port_outl[ base + c][0] == outl) + port_outl[ base + c][0] = NULL; + } + if (port_priv[base + c][1] == priv) + { + if (port_inb[ base + c][1] == inb) + port_inb[ base + c][1] = NULL; + if (port_inw[ base + c][1] == inw) + port_inw[ base + c][1] = NULL; + if (port_inl[ base + c][1] == inl) + port_inl[ base + c][1] = NULL; + if (port_outb[ base + c][1] == outb) + port_outb[ base + c][1] = NULL; + if (port_outw[ base + c][1] == outw) + port_outw[ base + c][1] = NULL; + if (port_outl[ base + c][1] == outl) + port_outl[ base + c][1] = NULL; + } + } +} + +uint8_t cgamode,cgastat=0,cgacol; +int hsync; +uint8_t lpt2dat; +int sw9; +int t237=0; +uint8_t inb(uint16_t port) +{ + uint8_t temp = 0xff; + + if (port_inb[port][0]) + temp &= port_inb[port][0](port, port_priv[port][0]); + if (port_inb[port][1]) + temp &= port_inb[port][1](port, port_priv[port][1]); + + /* if (!port_inb[port][0] && !port_inb[port][1]) + pclog("Bad INB %04X %04X:%04X\n", port, CS, pc); */ + + return temp; +} + +uint8_t cpu_readport(uint32_t port) { return inb(port); } + +void outb(uint16_t port, uint8_t val) +{ + if (port_outb[port][0]) + port_outb[port][0](port, val, port_priv[port][0]); + if (port_outb[port][1]) + port_outb[port][1](port, val, port_priv[port][1]); + + /* if (!port_outb[port][0] && !port_outb[port][1]) + pclog("Bad OUTB %04X %02X %04X:%08X\n", port, val, CS, pc); */ + return; +} + +uint16_t inw(uint16_t port) +{ +// pclog("INW %04X\n", port); + if (port_inw[port][0]) + return port_inw[port][0](port, port_priv[port][0]); + if (port_inw[port][1]) + return port_inw[port][1](port, port_priv[port][1]); + + return inb(port) | (inb(port + 1) << 8); +} + +void outw(uint16_t port, uint16_t val) +{ +// printf("OUTW %04X %04X %04X:%08X\n",port,val, CS, pc); +/* if ((port & ~0xf) == 0xf000) + pclog("OUTW %04X %04X\n", port, val);*/ + + if (port_outw[port][0]) + port_outw[port][0](port, val, port_priv[port][0]); + if (port_outw[port][1]) + port_outw[port][1](port, val, port_priv[port][1]); + + if (port_outw[port][0] || port_outw[port][1]) + return; + + outb(port,val); + outb(port+1,val>>8); +} + +uint32_t inl(uint16_t port) +{ +// pclog("INL %04X\n", port); + if (port_inl[port][0]) + return port_inl[port][0](port, port_priv[port][0]); + if (port_inl[port][1]) + return port_inl[port][1](port, port_priv[port][1]); + + return inw(port) | (inw(port + 2) << 16); +} + +void outl(uint16_t port, uint32_t val) +{ +/* if ((port & ~0xf) == 0xf000) + pclog("OUTL %04X %08X\n", port, val);*/ + + if (port_outl[port][0]) + port_outl[port][0](port, val, port_priv[port][0]); + if (port_outl[port][1]) + port_outl[port][1](port, val, port_priv[port][1]); + + if (port_outl[port][0] || port_outl[port][1]) + return; + + outw(port, val); + outw(port + 2, val >> 16); +} diff --git a/src/io.h b/src/io.h new file mode 100644 index 000000000..84792374d --- /dev/null +++ b/src/io.h @@ -0,0 +1,19 @@ +void io_init(); + +void io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); + +void io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); diff --git a/src/jim.c b/src/jim.c new file mode 100644 index 000000000..54f7d1a65 --- /dev/null +++ b/src/jim.c @@ -0,0 +1,79 @@ +#include +#include +#include "ibm.h" +#include "io.h" + +uint8_t europcdat[16]; +struct +{ + uint8_t dat[16]; + int stat; + int addr; +} europc_rtc; + +void writejim(uint16_t addr, uint8_t val, void *p) +{ + if ((addr&0xFF0)==0x250) europcdat[addr&0xF]=val; + switch (addr) + { + case 0x25A: +// printf("Write RTC stat %i val %02X\n",europc_rtc.stat,val); + switch (europc_rtc.stat) + { + case 0: + europc_rtc.addr=val&0xF; + europc_rtc.stat++; +// printf("RTC addr now %02X - contents %02X\n",val&0xF,europc_rtc.dat[europc_rtc.addr]); + break; + case 1: + europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF)|(val<<4); + europc_rtc.stat++; + break; + case 2: + europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF0)|(val&0xF); + europc_rtc.stat=0; + break; + } + break; + } +// printf("Write JIM %04X %02X\n",addr,val); +} + +uint8_t readjim(uint16_t addr, void *p) +{ +// printf("Read JIM %04X\n",addr); + switch (addr) + { + case 0x250: case 0x251: case 0x252: case 0x253: return 0; + case 0x254: case 0x255: case 0x256: case 0x257: return europcdat[addr&0xF]; + case 0x25A: + if (europc_rtc.stat==1) + { + europc_rtc.stat=2; + return europc_rtc.dat[europc_rtc.addr]>>4; + } + if (europc_rtc.stat==2) + { + europc_rtc.stat=0; + return europc_rtc.dat[europc_rtc.addr]&0xF; + } + return 0; + } + return 0; +} + +void jim_init() +{ + uint8_t viddat; + memset(europc_rtc.dat,0,16); + europc_rtc.dat[0xF]=1; + europc_rtc.dat[3]=1; + europc_rtc.dat[4]=1; + europc_rtc.dat[5]=0x88; + if (gfxcard==GFX_CGA) viddat=0x12; + else if (gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_INCOLOR) viddat=3; + else viddat=0x10; + europc_rtc.dat[0xB]=viddat; + europc_rtc.dat[0xD]=viddat; /*Checksum*/ + io_sethandler(0x250, 0x10, readjim, NULL, NULL, writejim, NULL, NULL, NULL); +} diff --git a/src/jim.h b/src/jim.h new file mode 100644 index 000000000..632d31e03 --- /dev/null +++ b/src/jim.h @@ -0,0 +1 @@ +void jim_init(); diff --git a/src/joystick_standard.c b/src/joystick_standard.c new file mode 100644 index 000000000..6f961a896 --- /dev/null +++ b/src/joystick_standard.c @@ -0,0 +1,208 @@ +#include +#include "ibm.h" +#include "device.h" +#include "timer.h" +#include "gameport.h" +#include "joystick_standard.h" +#include "plat-joystick.h" + +static void *joystick_standard_init() +{ +} + +static void joystick_standard_close(void *p) +{ +} + +static uint8_t joystick_standard_read(void *p) +{ + uint8_t ret = 0xf0; + + if (JOYSTICK_PRESENT(0)) + { + if (joystick_state[0].button[0]) + ret &= ~0x10; + if (joystick_state[0].button[1]) + ret &= ~0x20; + } + if (JOYSTICK_PRESENT(1)) + { + if (joystick_state[1].button[0]) + ret &= ~0x40; + if (joystick_state[1].button[1]) + ret &= ~0x80; + } + + return ret; +} + +static uint8_t joystick_standard_read_4button(void *p) +{ + uint8_t ret = 0xf0; + + if (JOYSTICK_PRESENT(0)) + { + if (joystick_state[0].button[0]) + ret &= ~0x10; + if (joystick_state[0].button[1]) + ret &= ~0x20; + if (joystick_state[0].button[2]) + ret &= ~0x40; + if (joystick_state[0].button[3]) + ret &= ~0x80; + } + + return ret; +} + +static void joystick_standard_write(void *p) +{ +} + +static int joystick_standard_read_axis(void *p, int axis) +{ + switch (axis) + { + case 0: + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + return joystick_state[0].axis[0]; + case 1: + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + return joystick_state[0].axis[1]; + case 2: + if (!JOYSTICK_PRESENT(1)) + return AXIS_NOT_PRESENT; + return joystick_state[1].axis[0]; + case 3: + if (!JOYSTICK_PRESENT(1)) + return AXIS_NOT_PRESENT; + return joystick_state[1].axis[1]; + } +} + +static int joystick_standard_read_axis_4button(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return 0; + case 3: + return 0; + } +} +static int joystick_standard_read_axis_6button(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return joystick_state[0].button[4] ? -32767 : 32768; + case 3: + return joystick_state[0].button[5] ? -32767 : 32768; + } +} +static int joystick_standard_read_axis_8button(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + if (joystick_state[0].button[4]) + return -32767; + if (joystick_state[0].button[6]) + return 32768; + return 0; + case 3: + if (joystick_state[0].button[5]) + return -32767; + if (joystick_state[0].button[7]) + return 32768; + return 0; + } +} + +static void joystick_standard_a0_over(void *p) +{ +} + +joystick_if_t joystick_standard = +{ + .name = "Standard 2-button joystick(s)", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis, + .a0_over = joystick_standard_a0_over, + .max_joysticks = 2, + .axis_count = 2, + .button_count = 2, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"Button 1", "Button 2"} +}; +joystick_if_t joystick_standard_4button = +{ + .name = "Standard 4-button joystick", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_4button, + .a0_over = joystick_standard_a0_over, + .max_joysticks = 1, + .axis_count = 2, + .button_count = 4, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"Button 1", "Button 2", "Button 3", "Button 4"} +}; +joystick_if_t joystick_standard_6button = +{ + .name = "Standard 6-button joystick", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_6button, + .a0_over = joystick_standard_a0_over, + .max_joysticks = 1, + .axis_count = 2, + .button_count = 6, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6"} +}; +joystick_if_t joystick_standard_8button = +{ + .name = "Standard 8-button joystick", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_8button, + .a0_over = joystick_standard_a0_over, + .max_joysticks = 1, + .axis_count = 2, + .button_count = 8, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6", "Button 7", "Button 8"} +}; diff --git a/src/joystick_standard.h b/src/joystick_standard.h new file mode 100644 index 000000000..7150058a8 --- /dev/null +++ b/src/joystick_standard.h @@ -0,0 +1,4 @@ +extern joystick_if_t joystick_standard; +extern joystick_if_t joystick_standard_4button; +extern joystick_if_t joystick_standard_6button; +extern joystick_if_t joystick_standard_8button; diff --git a/src/joystick_sw_pad.c b/src/joystick_sw_pad.c new file mode 100644 index 000000000..007dd5492 --- /dev/null +++ b/src/joystick_sw_pad.c @@ -0,0 +1,251 @@ +/*Sidewinder game pad notes : + + - Write to 0x201 starts packet transfer (5*N or 15*N bits) + - Currently alternates between Mode A and Mode B (is there any way of + actually controlling which is used?) + - Windows 9x drivers require Mode B when more than 1 pad connected + - Packet preceeded by high data (currently 50us), and followed by low + data (currently 160us) - timings are probably wrong, but good enough + for everything I've tried + - Analogue inputs are only used to time ID packet request. If A0 timing + out is followed after ~64us by another 0x201 write then an ID packet + is triggered + - Sidewinder game pad ID is 'H0003' + - ID is sent in Mode A (1 bit per clock), but data bit 2 must change + during ID packet transfer, or Windows 9x drivers won't use Mode B. I + don't know if it oscillates, mirrors the data transfer, or something + else - the drivers only check that it changes at least 10 times during + the transfer + - Some DOS stuff will write to 0x201 while a packet is being transferred. + This seems to be ignored. +*/ + +#include +#include "ibm.h" +#include "device.h" +#include "timer.h" +#include "gameport.h" +#include "joystick_sw_pad.h" +#include "plat-joystick.h" + +typedef struct +{ + int poll_time; + int poll_left; + int poll_clock; + uint64_t poll_data; + int poll_mode; + + int trigger_time; + int data_mode; +} sw_data; + +static void sw_timer_over(void *p) +{ + sw_data *sw = (sw_data *)p; + + while (sw->poll_time <= 0 && sw->poll_left) + { + sw->poll_clock = !sw->poll_clock; + + if (sw->poll_clock) + { + sw->poll_data >>= (sw->poll_mode ? 3 : 1); + sw->poll_left--; + } + + if (sw->poll_left == 1 && !sw->poll_clock) + sw->poll_time += TIMER_USEC * 160; + else if (sw->poll_left) + sw->poll_time += TIMER_USEC * 5; + else + sw->poll_time = 0; + } + + if (!sw->poll_left) + sw->poll_time = 0; +} + +static void sw_trigger_timer_over(void *p) +{ + sw_data *sw = (sw_data *)p; + + sw->trigger_time = 0; +} + +static int sw_parity(uint16_t data) +{ + int bits_set = 0; + + while (data) + { + bits_set++; + data &= (data - 1); + } + + return bits_set & 1; +} + +static void *sw_init() +{ + sw_data *sw = (sw_data *)malloc(sizeof(sw_data)); + memset(sw, 0, sizeof(sw_data)); + + timer_add(sw_timer_over, &sw->poll_time, &sw->poll_time, sw); + timer_add(sw_trigger_timer_over, &sw->trigger_time, &sw->trigger_time, sw); + + return sw; +} + +static void sw_close(void *p) +{ + sw_data *sw = (sw_data *)p; + + free(sw); +} + +static uint8_t sw_read(void *p) +{ + sw_data *sw = (sw_data *)p; + uint8_t temp = 0; + + if (!JOYSTICK_PRESENT(0)) + return 0xff; + + if (sw->poll_time) + { + if (sw->poll_clock) + temp |= 0x10; + + if (sw->poll_mode) + temp |= (sw->poll_data & 7) << 5; + else + { + temp |= ((sw->poll_data & 1) << 5) | 0xc0; + if (sw->poll_left > 31 && !(sw->poll_left & 1)) + temp &= ~0x80; + } + } + else + temp |= 0xf0; + + return temp; +} + +static void sw_write(void *p) +{ + sw_data *sw = (sw_data *)p; + int time_since_last = sw->trigger_time / TIMER_USEC; + + if (!JOYSTICK_PRESENT(0)) + return; + + timer_process(); + + if (!sw->poll_left) + { + sw->poll_clock = 1; + sw->poll_time = TIMER_USEC * 50; + + if (time_since_last > 9900 && time_since_last < 9940) + { +// pclog("sw sends ID packet\n"); + sw->poll_mode = 0; + sw->poll_left = 49; + sw->poll_data = 0x2400ull | (0x1830ull << 15) | (0x19b0ull << 30); + } + else + { + int c; + +// pclog("sw sends data packet %08x %i\n", cpu_state.pc, data_packets++); + + sw->poll_mode = sw->data_mode; + sw->data_mode = !sw->data_mode; + + if (sw->poll_mode) + { + sw->poll_left = 1; + sw->poll_data = 7; + } + else + { + sw->poll_left = 1; + sw->poll_data = 1; + } + + for (c = 0; c < 4; c++) + { + uint64_t data = 0x3fff; + int b; + + if (!JOYSTICK_PRESENT(c)) + break; + + if (joystick_state[c].axis[1] < -16383) + data &= ~1; + if (joystick_state[c].axis[1] > 16383) + data &= ~2; + if (joystick_state[c].axis[0] > 16383) + data &= ~4; + if (joystick_state[c].axis[0] < -16383) + data &= ~8; + + for (b = 0; b < 10; b++) + { + if (joystick_state[c].button[b]) + data &= ~(1 << (b + 4)); + } + + if (sw_parity(data)) + data |= 0x4000; + + if (sw->poll_mode) + { + sw->poll_left += 5; + sw->poll_data |= (data << (c*15 + 3)); + } + else + { + sw->poll_left += 15; + sw->poll_data |= (data << (c*15 + 1)); + } + } + } + } + + sw->trigger_time = 0; + + timer_update_outstanding(); +} + +static int sw_read_axis(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + return 0; /*No analogue support on Sidewinder game pad*/ +} + +static void sw_a0_over(void *p) +{ + sw_data *sw = (sw_data *)p; + + sw->trigger_time = TIMER_USEC * 10000; +} + +joystick_if_t joystick_sw_pad = +{ + .name = "Microsoft SideWinder Pad", + .init = sw_init, + .close = sw_close, + .read = sw_read, + .write = sw_write, + .read_axis = sw_read_axis, + .a0_over = sw_a0_over, + .max_joysticks = 4, + .axis_count = 2, + .button_count = 10, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"A", "B", "C", "X", "Y", "Z", "L", "R", "Start", "M"} +}; diff --git a/src/joystick_sw_pad.h b/src/joystick_sw_pad.h new file mode 100644 index 000000000..ba5ceb680 --- /dev/null +++ b/src/joystick_sw_pad.h @@ -0,0 +1 @@ +extern joystick_if_t joystick_sw_pad; diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 000000000..f1ad9d31d --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,503 @@ +#include "ibm.h" +#include "plat-keyboard.h" +#include "keyboard.h" + +int keybsendcallback = 0; + +typedef struct +{ + int scancodes_make[9]; + int scancodes_break[9]; +} scancode; + +/*272 = 256 + 16 fake interim scancodes for disambiguation purposes.*/ +static scancode scancode_set1[272] = +{ + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, + { {0x54, -1}, {0xd4, -1} }, { {0x55, -1}, {0xd5, -1} }, { {0x56, -1}, {0xd6, -1} }, { {0x57, -1}, {0xd7, -1} }, + { {0x58, -1}, {0xd8, -1} }, { {0x59, -1}, {0xd9, -1} }, { {0x5a, -1}, {0xda, -1} }, { {0x5b, -1}, {0xdb, -1} }, + { {0x5c, -1}, {0xdc, -1} }, { {0x5d, -1}, {0xdd, -1} }, { {0x5e, -1}, {0xde, -1} }, { {0x5f, -1}, {0xdf, -1} }, + { {0x60, -1}, {0xe0, -1} }, { {0x61, -1}, {0xe1, -1} }, { {0x62, -1}, {0xe2, -1} }, { {0x63, -1}, {0xe3, -1} }, + { {0x64, -1}, {0xe4, -1} }, { {0x65, -1}, {0xe5, -1} }, { {0x66, -1}, {0xe6, -1} }, { {0x67, -1}, {0xe7, -1} }, + { {0x68, -1}, {0xe8, -1} }, { {0x69, -1}, {0xe9, -1} }, { {0x6a, -1}, {0xea, -1} }, { {0x6b, -1}, {0xeb, -1} }, + { {0x6c, -1}, {0xec, -1} }, { {0x6d, -1}, {0xed, -1} }, { {0x6e, -1}, {0xee, -1} }, { {0x6f, -1}, {0xef, -1} }, + { {0x70, -1}, {0xf0, -1} }, { {0x71, -1}, {0xf1, -1} }, { {0x72, -1}, {0xf2, -1} }, { {0x73, -1}, {0xf3, -1} }, + { {0x74, -1}, {0xf4, -1} }, { {0x75, -1}, {0xf5, -1} }, { {0x76, -1}, {0xf6, -1} }, { {0x77, -1}, {0xf7, -1} }, + { {0x78, -1}, {0xf8, -1} }, { {0x79, -1}, {0xf9, -1} }, { {0x7a, -1}, {0xfa, -1} }, { {0x7b, -1}, {0xfb, -1} }, + { {0x7c, -1}, {0xfc, -1} }, { {0x7d, -1}, {0xfd, -1} }, { {0x7e, -1}, {0xfe, -1} }, { {0x7f, -1}, {0xff, -1} }, + + { {0x80, -1}, {-1} }, { {0x81, -1}, {-1} }, { {0x82, -1}, {-1} }, { {0xe0, 0x03, -1}, {0xe0, 0x83, -1} }, /*80*/ + { {0xe0, 0x04, -1}, {0xe0, 0x84, -1} }, { {0x85, -1}, {-1} }, { {0x86, -1}, {-1} }, { {0x87, -1}, {-1} }, /*84*/ + { {0xe0, 0x08, -1}, {0xe0, 0x88, -1} }, { {0xe0, 0x09, -1}, {0xe0, 0x89, -1} }, { {0xe0, 0x0a, -1}, {0xe0, 0x8a, -1} }, { {0xe0, 0x0b, -1}, {0xe0, 0x8b, -1} }, /*88*/ + { {0xe0, 0x0c, -1}, {0xe0, 0x8c, -1} }, { {-1}, {-1} }, { {0xe0, 0x0e, -1}, {0xe0, 0x8e, -1} }, { {0xe0, 0x0f, -1}, {0xe0, 0x8f, -1} }, /*8c*/ + { {0xe0, 0x10, -1}, {0xe0, 0x90, -1} }, { {0xe0, 0x11, -1}, {0xe0, 0x91, -1} }, { {0xe0, 0x12, -1}, {0xe0, 0x92, -1} }, { {0xe0, 0x13, -1}, {0xe0, 0x93, -1} }, /*90*/ + { {0xe0, 0x14, -1}, {0xe0, 0x94, -1} }, { {0xe0, 0x15, -1}, {0xe0, 0x95, -1} }, { {0xe0, 0x16, -1}, {0xe0, 0x96, -1} }, { {0xe0, 0x17, -1}, {0xe0, 0x97, -1} }, /*94*/ + { {0xe0, 0x18, -1}, {0xe0, 0x98, -1} }, { {0xe0, 0x19, -1}, {0xe0, 0x99, -1} }, { {0xe0, 0x1a, -1}, {0xe0, 0x9a, -1} }, { {0xe0, 0x1b, -1}, {0xe0, 0x9b, -1} }, /*98*/ + { {0xe0, 0x1c, -1}, {0xe0, 0x9c, -1} }, { {0xe0, 0x1d, -1}, {0xe0, 0x9d, -1} }, { {0xe0, 0x1e, -1}, {0xe0, 0x9e, -1} }, { {0xe0, 0x1f, -1}, {0xe0, 0x9f, -1} }, /*9c*/ + { {0xe0, 0x20, -1}, {0xe0, 0xa0, -1} }, { {0xe0, 0x21, -1}, {0xe0, 0xa1, -1} }, { {0xe0, 0x22, -1}, {0xe0, 0xa2, -1} }, { {0xe0, 0x23, -1}, {0xe0, 0xa3, -1} }, /*a0*/ + { {0xe0, 0x24, -1}, {0xe0, 0xa4, -1} }, { {0xe0, 0x25, -1}, {0xe0, 0xa5, -1} }, { {0xe0, 0x26, -1}, {0xe0, 0xa6, -1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a8*/ + { {0xe0, 0x2c, -1}, {0xe0, 0xac, -1} }, { {0xe0, 0x2d, -1}, {0xe0, 0xad, -1} }, { {0xe0, 0x2e, -1}, {0xe0, 0xae, -1} }, { {0xe0, 0x2f, -1}, {0xe0, 0xaf, -1} }, /*ac*/ + { {0xe0, 0x30, -1}, {0xe0, 0xb0, -1} }, { {0xe0, 0x31, -1}, {0xe0, 0xb1, -1} }, { {0xe0, 0x32, -1}, {0xe0, 0xb2, -1} }, { {-1}, {-1} }, /*b0*/ + { {0xe0, 0x34, -1}, {0xe0, 0xb4, -1} }, { {0xe0, 0x35, -1}, {0xe0, 0xb5, -1} }, { {-1}, {-1} }, { {0xe0, 0x37, -1}, {0xe0, 0xb7, -1} }, /*b4*/ + { {0xe0, 0x38, -1}, {0xe0, 0xb8, -1} }, { {-1}, {-1} }, { {0xe0, 0x3a, -1}, {0xe0, 0xba, -1} }, { {0xe0, 0x3b, -1}, {0xe0, 0xbb, -1} }, /*b8*/ + { {0xe0, 0x3c, -1}, {0xe0, 0xbc, -1} }, { {0xe0, 0x3d, -1}, {0xe0, 0xbd, -1} }, { {0xe0, 0x3e, -1}, {0xe0, 0xbe, -1} }, { {0xe0, 0x3f, -1}, {0xe0, 0xbf, -1} }, /*bc*/ + { {0xe0, 0x40, -1}, {0xe0, 0xc0, -1} }, { {0xe0, 0x41, -1}, {0xe0, 0xc1, -1} }, { {0xe0, 0x42, -1}, {0xe0, 0xc2, -1} }, { {0xe0, 0x43, -1}, {0xe0, 0xc3, -1} }, /*c0*/ + { {0xe0, 0x44, -1}, {0xe0, 0xc4, -1} }, { {-1}, {-1} }, { {0xe0, 0x46, -1}, {0xe0, 0xc6, -1} }, { {0xe0, 0xaa, 0xe0, 0x47, -1}, {0xe0, 0xc7, 0xe0, 0x2a, -1} }, /*c4*/ + { {0xe0, 0xaa, 0xe0, 0x48, -1}, {0xe0, 0xc8, 0xe0, 0x2a, -1} }, { {0xe0, 0xaa, 0xe0, 0x49, -1}, {0xe0, 0xc9, 0xe0, 0x2a, -1} }, { {-1}, {-1} }, { {0xe, 0xaa, 0xe0, 0x4b, -1}, {0xe0, 0xcb, 0xe0, 0x2a, -1} }, /*c8*/ + { {0xe0, 0x4c, -1}, {0xe0, 0xcc, -1} }, { {0xe0, 0xaa, 0xe0, 0x4d, -1}, {0xe0, 0xcd, 0xe0, 0x2a, -1} }, { {0xe0, 0x4e, -1}, {0xe0, 0xce, -1} }, { {0xe0, 0xaa, 0xe0, 0x4f, -1}, {0xe0, 0xcf, 0xe0, 0x2a, -1} }, /*cc*/ + { {0xe0, 0xaa, 0xe0, 0x50, -1}, {0xe0, 0xd0, 0xe0, 0x2a, -1} }, { {0xe0, 0xaa, 0xe0, 0x51, -1}, {0xe0, 0xd1, 0xe0, 0x2a, -1} }, { {0xe0, 0xaa, 0xe0, 0x52, -1}, {0xe0, 0xd2, 0xe0, 0x2a, -1} }, { {0xe0, 0xaa, 0xe0, 0x53, -1}, {0xe0, 0xd3, 0xe0, 0x2a, -1} }, /*d0*/ + { {0xd4, -1}, {-1} }, { {0xe0, 0x55, -1}, {0xe0, 0xd5, -1} }, { {-1}, {-1} }, { {0xe0, 0x57, -1}, {0xe0, 0xd7, -1} }, /*d4*/ + { {0xe0, 0x58, -1}, {0xe0, 0xd8, -1} }, { {0xe0, 0x59, -1}, {0xe0, 0xd9, -1} }, { {0xe0, 0x5a, -1}, {0xe0, 0xaa, -1} }, { {0xe0, 0x5b, -1}, {0xe0, 0xdb, -1} }, /*d8*/ + { {0xe0, 0x5c, -1}, {0xe0, 0xdc, -1} }, { {0xe0, 0x5d, -1}, {0xe0, 0xdd, -1} }, { {0xe0, 0x5e, -1}, {0xe0, 0xee, -1} }, { {0xe0, 0x5f, -1}, {0xe0, 0xdf, -1} }, /*dc*/ + { {-1}, {-1} }, { {0xe0, 0x61, -1}, {0xe0, 0xe1, -1} }, { {0xe0, 0x62, -1}, {0xe0, 0xe2, -1} }, { {0xe0, 0x63, -1}, {0xe0, 0xe3, -1} }, /*e0*/ + { {0xe0, 0x64, -1}, {0xe0, 0xe4, -1} }, { {0xe0, 0x65, -1}, {0xe0, 0xe5, -1} }, { {0xe0, 0x66, -1}, {0xe0, 0xe6, -1} }, { {0xe0, 0x67, -1}, {0xe0, 0xe7, -1} }, /*e4*/ + { {0xe0, 0x68, -1}, {0xe0, 0xe8, -1} }, { {0xe0, 0x69, -1}, {0xe0, 0xe9, -1} }, { {0xe0, 0x6a, -1}, {0xe0, 0xea, -1} }, { {0xe0, 0x6b, -1}, {0xe0, 0xeb, -1} }, /*e8*/ + { {0xe0, 0x6c, -1}, {0xe0, 0xec, -1} }, { {0xe0, 0x6d, -1}, {0xe0, 0xed, -1} }, { {0xe0, 0x6e, -1}, {0xe0, 0xee, -1} }, { {-1}, {-1} }, /*ec*/ + { {0xe0, 0x70, -1}, {0xe0, 0xf0, -1} }, { {0xf1, -1}, {-1} }, { {0xf2, -1}, {-1} }, { {0xe0, 0x73, -1}, {0xe0, 0xf3, -1} }, /*f0*/ + { {0xe0, 0x74, -1}, {0xe0, 0xf4, -1} }, { {0xe0, 0x75, -1}, {0xe0, 0xf5, -1} }, { {-1}, {-1} }, { {0xe0, 0x77, -1}, {0xe0, 0xf7, -1} }, /*f4*/ + { {0xe0, 0x78, -1}, {0xe0, 0xf8, -1} }, { {0xe0, 0x79, -1}, {0xe0, 0xf9, -1} }, { {0xe0, 0x7a, -1}, {0xe0, 0xfa, -1} }, { {0xe0, 0x7b, -1}, {0xe0, 0xfb, -1} }, /*f8*/ + { {0xe0, 0x7c, -1}, {0xe0, 0xfc, -1} }, { {0xe0, 0x7d, -1}, {0xe0, 0xfd, -1} }, { {0xe0, 0x7e, -1}, {0xe0, 0xfe, -1} }, { {0xe1, 0x1d, -1}, {0xe1, 0x9d, -1} }, /*fc*/ + + { {-1}, {-1} }, { {0xe0, 0x01, -1}, {0xe0, 0x81, -1} }, { {0xe0, 0x02, -1}, {0xe0, 0x82, -1} }, { {0xe0, 0xaa, -1}, {0xe0, 0x2a, -1} }, /*100*/ + { {-1}, {-1} }, { {0xe0, 0x05, -1}, {0xe0, 0x85, -1} }, { {0xe0, 0x06, -1}, {0xe0, 0x86, -1} }, { {0xe0, 0x07, -1}, {0xe0, 0x87, -1} }, /*104*/ + { {0xe0, 0x71, -1}, {0xe0, 0xf1, -1} }, { {0xe0, 0x72, -1}, {0xe0, 0xf2, -1} }, { {0xe0, 0x7f, -1}, {0xe0, 0xff, -1} }, { {0xe0, 0xe1, -1}, {-1} }, /*108*/ + { {0xe0, 0xee, -1}, {-1} }, { {0xe0, 0xf1, -1}, {-1} }, { {0xe0, 0xfe, -1}, {-1} }, { {0xe0, 0xff, -1}, {-1} } /*10c*/ +}; + +static scancode scancode_set2[272] = +{ + { {-1}, {-1} }, { {0x76, -1}, {0xF0, 0x76, -1} }, { {0x16, -1}, {0xF0, 0x16, -1} }, { {0x1E, -1}, {0xF0, 0x1E, -1} }, + { {0x26, -1}, {0xF0, 0x26, -1} }, { {0x25, -1}, {0xF0, 0x25, -1} }, { {0x2E, -1}, {0xF0, 0x2E, -1} }, { {0x36, -1}, {0xF0, 0x36, -1} }, + { {0x3D, -1}, {0xF0, 0x3D, -1} }, { {0x3E, -1}, {0xF0, 0x3E, -1} }, { {0x46, -1}, {0xF0, 0x46, -1} }, { {0x45, -1}, {0xF0, 0x45, -1} }, + { {0x4E, -1}, {0xF0, 0x4E, -1} }, { {0x55, -1}, {0xF0, 0x55, -1} }, { {0x66, -1}, {0xF0, 0x66, -1} }, { {0x0D, -1}, {0xF0, 0x0D, -1} }, + { {0x15, -1}, {0xF0, 0x15, -1} }, { {0x1D, -1}, {0xF0, 0x1D, -1} }, { {0x24, -1}, {0xF0, 0x24, -1} }, { {0x2D, -1}, {0xF0, 0x2D, -1} }, + { {0x2C, -1}, {0xF0, 0x2C, -1} }, { {0x35, -1}, {0xF0, 0x35, -1} }, { {0x3C, -1}, {0xF0, 0x3C, -1} }, { {0x43, -1}, {0xF0, 0x43, -1} }, + { {0x44, -1}, {0xF0, 0x44, -1} }, { {0x4D, -1}, {0xF0, 0x4D, -1} }, { {0x54, -1}, {0xF0, 0x54, -1} }, { {0x5B, -1}, {0xF0, 0x5B, -1} }, + { {0x5A, -1}, {0xF0, 0x5A, -1} }, { {0x14, -1}, {0xF0, 0x14, -1} }, { {0x1C, -1}, {0xF0, 0x1C, -1} }, { {0x1B, -1}, {0xF0, 0x1B, -1} }, + { {0x23, -1}, {0xF0, 0x23, -1} }, { {0x2B, -1}, {0xF0, 0x2B, -1} }, { {0x34, -1}, {0xF0, 0x34, -1} }, { {0x33, -1}, {0xF0, 0x33, -1} }, + { {0x3B, -1}, {0xF0, 0x3B, -1} }, { {0x42, -1}, {0xF0, 0x42, -1} }, { {0x4B, -1}, {0xF0, 0x4B, -1} }, { {0x4C, -1}, {0xF0, 0x4C, -1} }, + { {0x52, -1}, {0xF0, 0x52, -1} }, { {0x0E, -1}, {0xF0, 0x0E, -1} }, { {0x12, -1}, {0xF0, 0x12, -1} }, { {0x5D, -1}, {0xF0, 0x5D, -1} }, + { {0x1A, -1}, {0xF0, 0x1A, -1} }, { {0x22, -1}, {0xF0, 0x22, -1} }, { {0x21, -1}, {0xF0, 0x21, -1} }, { {0x2A, -1}, {0xF0, 0x2A, -1} }, + { {0x32, -1}, {0xF0, 0x32, -1} }, { {0x31, -1}, {0xF0, 0x31, -1} }, { {0x3A, -1}, {0xF0, 0x3A, -1} }, { {0x41, -1}, {0xF0, 0x41, -1} }, + { {0x49, -1}, {0xF0, 0x49, -1} }, { {0x4A, -1}, {0xF0, 0x4A, -1} }, { {0x59, -1}, {0xF0, 0x59, -1} }, { {0x7C, -1}, {0xF0, 0x7C, -1} }, + { {0x11, -1}, {0xF0, 0x11, -1} }, { {0x29, -1}, {0xF0, 0x29, -1} }, { {0x58, -1}, {0xF0, 0x58, -1} }, { {0x05, -1}, {0xF0, 0x05, -1} }, + { {0x06, -1}, {0xF0, 0x06, -1} }, { {0x04, -1}, {0xF0, 0x04, -1} }, { {0x0C, -1}, {0xF0, 0x0C, -1} }, { {0x03, -1}, {0xF0, 0x03, -1} }, + { {0x0B, -1}, {0xF0, 0x0B, -1} }, { {0x83, -1}, {0xF0, 0x83, -1} }, { {0x0A, -1}, {0xF0, 0x0A, -1} }, { {0x01, -1}, {0xF0, 0x01, -1} }, + { {0x09, -1}, {0xF0, 0x09, -1} }, { {0x77, -1}, {0xF0, 0x77, -1} }, { {0x7E, -1}, {0xF0, 0x7E, -1} }, { {0x6C, -1}, {0xF0, 0x6C, -1} }, + { {0x75, -1}, {0xF0, 0x75, -1} }, { {0x7D, -1}, {0xF0, 0x7D, -1} }, { {0x7B, -1}, {0xF0, 0x7B, -1} }, { {0x6B, -1}, {0xF0, 0x6B, -1} }, + { {0x73, -1}, {0xF0, 0x73, -1} }, { {0x74, -1}, {0xF0, 0x74, -1} }, { {0x79, -1}, {0xF0, 0x79, -1} }, { {0x69, -1}, {0xF0, 0x69, -1} }, + { {0x72, -1}, {0xF0, 0x72, -1} }, { {0x7A, -1}, {0xF0, 0x7A, -1} }, { {0x70, -1}, {0xF0, 0x70, -1} }, { {0x71, -1}, {0xF0, 0x71, -1} }, + { {0x84, -1}, {0xF0, 0x84, -1} }, { {0x60, -1}, {0xF0, 0x60, -1} }, { {0x61, -1}, {0xF0, 0x61, -1} }, { {0x78, -1}, {0xF0, 0x78, -1} }, /*54*/ + { {0x07, -1}, {0xF0, 0x07, -1} }, { {0x0F, -1}, {0xF0, 0x0F, -1} }, { {0x17, -1}, {0xF0, 0x17, -1} }, { {0x1F, -1}, {0xF0, 0x1F, -1} }, /*58*/ + { {0x27, -1}, {0xF0, 0x27, -1} }, { {0x2F, -1}, {0xF0, 0x2F, -1} }, { {0x37, -1}, {0xF0, 0x37, -1} }, { {0x3F, -1}, {0xF0, 0x3F, -1} }, /*5c*/ + { {0x47, -1}, {0xF0, 0x47, -1} }, { {0x4F, -1}, {0xF0, 0x4F, -1} }, { {0x56, -1}, {0xF0, 0x56, -1} }, { {0x5E, -1}, {0xF0, 0x5E, -1} }, /*60*/ + { {0x08, -1}, {0xF0, 0x08, -1} }, { {0x10, -1}, {0xF0, 0x10, -1} }, { {0x18, -1}, {0xF0, 0x18, -1} }, { {0x20, -1}, {0xF0, 0x20, -1} }, /*64*/ + { {0x28, -1}, {0xF0, 0x28, -1} }, { {0x30, -1}, {0xF0, 0x30, -1} }, { {0x38, -1}, {0xF0, 0x38, -1} }, { {0x40, -1}, {0xF0, 0x40, -1} }, /*68*/ + { {0x48, -1}, {0xF0, 0x48, -1} }, { {0x50, -1}, {0xF0, 0x50, -1} }, { {0x57, -1}, {0xF0, 0x57, -1} }, { {0x6F, -1}, {0xF0, 0x6F, -1} }, /*6c*/ + { {0x13, -1}, {0xF0, 0x13, -1} }, { {0x19, -1}, {0xF0, 0x19, -1} }, { {0x39, -1}, {0xF0, 0x39, -1} }, { {0x51, -1}, {0xF0, 0x51, -1} }, /*70*/ + { {0x53, -1}, {0xF0, 0x53, -1} }, { {0x5C, -1}, {0xF0, 0x5C, -1} }, { {0x5F, -1}, {0xF0, 0x5F, -1} }, { {0x62, -1}, {0xF0, 0x62, -1} }, /*74*/ + { {0x63, -1}, {0xF0, 0x63, -1} }, { {0x64, -1}, {0xF0, 0x64, -1} }, { {0x65, -1}, {0xF0, 0x65, -1} }, { {0x67, -1}, {0xF0, 0x67, -1} }, /*78*/ + { {0x68, -1}, {0xF0, 0x68, -1} }, { {0x6A, -1}, {0xF0, 0x6A, -1} }, { {0x6D, -1}, {0xF0, 0x6D, -1} }, { {0x6E, -1}, {0xF0, 0x6E, -1} }, /*7c*/ + + { {0x80, -1}, {0xF0, 0x80, -1} }, { {0x81, -1}, {0xF0, 0x81, -1} }, { {0x82, -1}, {0xF0, 0x82, -1} }, { {0xe0, 0x1E, -1}, {0xe0, 0xF0, 0x1E, -1} }, /*80*/ + { {0xe0, 0x26, -1}, {0xe0, 0xF0, 0x26, -1} }, { {0x85, -1}, {0xF0, 0x85, -1} }, { {0x86, -1}, {0xF0, 0x86, -1} }, { {0x87, -1}, {0xF0, 0x87, -1} }, /*84*/ + { {0xe0, 0x3D, -1}, {0xe0, 0xF0, 0x3D, -1} }, { {0xe0, 0x3E, -1}, {0xe0, 0xF0, 0x3E, -1} }, { {0xe0, 0x46, -1}, {0xe0, 0xF0, 0x46, -1} }, { {0xe0, 0x45, -1}, {0xe0, 0xF0, 0x45, -1} }, /*88*/ + { {0xe0, 0x4E, -1}, {0xe0, 0xF0, 0x4E, -1} }, { {-1}, {-1} }, { {0xe0, 0x66, -1}, {0xe0, 0xF0, 0x66, -1} }, { {0xe0, 0x0D, -1}, {0xe0, 0xF0, 0x0D, -1} }, /*8c*/ + { {0xe0, 0x15, -1}, {0xe0, 0xF0, 0x15, -1} }, { {0xe0, 0x1D, -1}, {0xe0, 0xF0, 0x1D, -1} }, { {0xe0, 0x24, -1}, {0xe0, 0xF0, 0x24, -1} }, { {0xe0, 0x2D, -1}, {0xe0, 0xF0, 0x2D, -1} }, /*90*/ + { {0xe0, 0x2C, -1}, {0xe0, 0xF0, 0x2C, -1} }, { {0xe0, 0x35, -1}, {0xe0, 0xF0, 0x35, -1} }, { {0xe0, 0x3C, -1}, {0xe0, 0xF0, 0x3C, -1} }, { {0xe0, 0x43, -1}, {0xe0, 0xF0, 0x43, -1} }, /*94*/ + { {0xe0, 0x44, -1}, {0xe0, 0xF0, 0x44, -1} }, { {0xe0, 0x4D, -1}, {0xe0, 0xF0, 0x4D, -1} }, { {0xe0, 0x54, -1}, {0xe0, 0xF0, 0x54, -1} }, { {0xe0, 0x5B, -1}, {0xe0, 0xF0, 0x5B, -1} }, /*98*/ + { {0xe0, 0x5A, -1}, {0xe0, 0xF0, 0x5A, -1} }, { {0xe0, 0x14, -1}, {0xe0, 0xF0, 0x14, -1} }, { {0xe0, 0x1C, -1}, {0xe0, 0xF0, 0x1C, -1} }, { {0xe0, 0x1B, -1}, {0xe0, 0xF0, 0x1B, -1} }, /*9c*/ + { {0xe0, 0x23, -1}, {0xe0, 0xF0, 0x23, -1} }, { {0xe0, 0x2B, -1}, {0xe0, 0xF0, 0x2B, -1} }, { {0xe0, 0x34, -1}, {0xe0, 0xF0, 0x34, -1} }, { {0xe0, 0x33, -1}, {0xe0, 0xF0, 0x33, -1} }, /*a0*/ + { {0xe0, 0x3B, -1}, {0xe0, 0xF0, 0x3B, -1} }, { {0xe0, 0x42, -1}, {0xe0, 0xF0, 0x42, -1} }, { {0xe0, 0x4B, -1}, {0xe0, 0xF0, 0x4B, -1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a8*/ + { {0xe0, 0x1A, -1}, {0xe0, 0xF0, 0x1A, -1} }, { {0xe0, 0x22, -1}, {0xe0, 0xF0, 0x22, -1} }, { {0xe0, 0x21, -1}, {0xe0, 0xF0, 0x21, -1} }, { {0xe0, 0x2A, -1}, {0xe0, 0xF0, 0x2A, -1} }, /*ac*/ + { {0xe0, 0x32, -1}, {0xe0, 0xF0, 0x32, -1} }, { {0xe0, 0x31, -1}, {0xe0, 0xF0, 0x31, -1} }, { {0xe0, 0x3A, -1}, {0xe0, 0xF0, 0x3A, -1} }, { {-1}, {-1} }, /*b0*/ + { {0xe0, 0x49, -1}, {0xe0, 0xF0, 0x49, -1} }, { {0xe0, 0x4A, -1}, {0xe0, 0xF0, 0x4A, -1} }, { {-1}, {-1} }, { {0xe0, 0x7C, -1}, {0xe0, 0xF0, 0x7C, -1} }, /*b4*/ + { {0xe0, 0x11, -1}, {0xe0, 0xF0, 0x11, -1} }, { {-1}, {-1} }, { {0xe0, 0x58, -1}, {0xe0, 0xF0, 0x58, -1} }, { {0xe0, 0x05, -1}, {0xe0, 0xF0, 0x05, -1} }, /*b8*/ + { {0xe0, 0x06, -1}, {0xe0, 0xF0, 0x06, -1} }, { {0xe0, 0x04, -1}, {0xe0, 0xF0, 0x04, -1} }, { {0xe0, 0x0C, -1}, {0xe0, 0xF0, 0x0C, -1} }, { {0xe0, 0x03, -1}, {0xe0, 0xF0, 0x03, -1} }, /*bc*/ + { {0xe0, 0x0B, -1}, {0xe0, 0xF0, 0x0B, -1} }, { {0xe0, 0x02, -1}, {0xe0, 0xF0, 0x02, -1} }, { {0xe0, 0x0A, -1}, {0xe0, 0xF0, 0x0A, -1} }, { {0xe0, 0x01, -1}, {0xe0, 0xF0, 0x01, -1} }, /*c0*/ + { {0xe0, 0x09, -1}, {0xe0, 0xF0, 0x09, -1} }, { {-1}, {-1} }, { {0xe0, 0x7E, -1}, {0xe0, 0xF0, 0x7E, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x6C, -1}, {0xe0, 0xF0, 0x6C, 0xe0, 0x12, -1} }, /*c4*/ + { {0xe0, 0xf0, 0x12, 0xe0, 0x75, -1}, {0xe0, 0xF0, 0x75, 0xe0, 0x12, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x7D, -1}, {0xe0, 0xF0, 0x7D, 0xe0, 0x12, -1} }, { {-1}, {-1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x6B, -1}, {0xe0, 0xF0, 0x6B, 0xe0, 0x12, -1} }, /*c8*/ + { {0xe0, 0x73, -1}, {0xe0, 0xF0, 0x73, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x74, -1}, {0xe0, 0xF0, 0x74, 0xe0, 0x12, -1} }, { {0xe0, 0x79, -1}, {0xe0, 0xF0, 0x79, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x69, -1}, {0xe0, 0xF0, 0x69, 0xe0, 0x12, -1} }, /*cc*/ + { {0xe0, 0xf0, 0x12, 0xe0, 0x72, -1}, {0xe0, 0xF0, 0x72, 0xe0, 0x12, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x7A, -1}, {0xe0, 0xF0, 0x7A, 0xe0, 0x12, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x70, -1}, {0xe0, 0xF0, 0x70, 0xe0, 0x12, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x71, -1}, {0xe0, 0xF0, 0x71, 0xe0, 0x12, -1} }, /*d0*/ + { {0xd4, -1}, {0xF0, 0xD4, -1} }, { {0xe0, 0x60, -1}, {0xe0, 0xF0, 0x60, -1} }, { {-1}, {-1} }, { {0xe0, 0x78, -1}, {0xe0, 0xF0, 0x78, -1} }, /*d4*/ + { {0xe0, 0x07, -1}, {0xe0, 0xF0, 0x07, -1} }, { {0xe0, 0x0F, -1}, {0xe0, 0xF0, 0x0F, -1} }, { {0xe0, 0x17, -1}, {0xe0, 0xF0, 0x17, -1} }, { {0xe0, 0x1F, -1}, {0xe0, 0xF0, 0x1F, -1} }, /*d8*/ + { {0xe0, 0x27, -1}, {0xe0, 0xF0, 0x27, -1} }, { {0xe0, 0x2F, -1}, {0xe0, 0xF0, 0x2F, -1} }, { {0xe0, 0x37, -1}, {0xe0, 0xF0, 0x37, -1} }, { {0xe0, 0x3F, -1}, {0xe0, 0xF0, 0x3F, -1} }, /*dc*/ + { {-1}, {-1} }, { {0xe0, 0x4F, -1}, {0xe0, 0xF0, 0x4F, -1} }, { {0xe0, 0x56, -1}, {0xe0, 0xF0, 0x56, -1} }, { {0xe0, 0x5E, -1}, {0xe0, 0xF0, 0x5E, -1} }, /*e0*/ + { {0xe0, 0x08, -1}, {0xe0, 0xF0, 0x08, -1} }, { {0xe0, 0x10, -1}, {0xe0, 0xF0, 0x10, -1} }, { {0xe0, 0x18, -1}, {0xe0, 0xF0, 0x18, -1} }, { {0xe0, 0x20, -1}, {0xe0, 0xF0, 0x20, -1} }, /*e4*/ + { {0xe0, 0x28, -1}, {0xe0, 0xF0, 0x28, -1} }, { {0xe0, 0x30, -1}, {0xe0, 0xF0, 0x30, -1} }, { {0xe0, 0x38, -1}, {0xe0, 0xF0, 0x38, -1} }, { {0xe0, 0x40, -1}, {0xe0, 0xF0, 0x40, -1} }, /*e8*/ + { {0xe0, 0x48, -1}, {0xe0, 0xF0, 0x48, -1} }, { {0xe0, 0x50, -1}, {0xe0, 0xF0, 0x50, -1} }, { {0xe0, 0x57, -1}, {0xe0, 0xF0, 0x57, -1} }, { {-1}, {-1} }, /*ec*/ + { {0xe0, 0x13, -1}, {0xe0, 0xF0, 0x13, -1} }, { {0xf1, -1}, {0xF0, 0xF1, -1} }, { {0xf2, -1}, {0xF0, 0xF2, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xF0, 0x51, -1} }, /*f0*/ + { {0xe0, 0x53, -1}, {0xe0, 0xF0, 0x53, -1} }, { {0xe0, 0x5C, -1}, {0xe0, 0xF0, 0x5C, -1} }, { {-1}, {-1} }, { {0xe0, 0x62, -1}, {0xe0, 0xF0, 0x62, -1} }, /*f4*/ + { {0xe0, 0x63, -1}, {0xe0, 0xF0, 0x63, -1} }, { {0xe0, 0x64, -1}, {0xe0, 0xF0, 0x64, -1} }, { {0xe0, 0x65, -1}, {0xe0, 0xF0, 0x65, -1} }, { {0xe0, 0x67, -1}, {0xe0, 0xF0, 0x67, -1} }, /*f8*/ + { {0xe0, 0x68, -1}, {0xe0, 0xF0, 0x68, -1} }, { {0xe0, 0x6A, -1}, {0xe0, 0xF0, 0x6A, -1} }, { {0xe0, 0x6D, -1}, {0xe0, 0xF0, 0x6D, -1} }, { {0xe1, 0x14, -1}, {0xe1, 0xf0, 0x14, -1} }, /*fc*/ + + { {-1}, {-1} }, { {0xe0, 0x76, -1}, {0xe0, 0xF0, 0x76, -1} }, { {0xe0, 0x16, -1}, {0xe0, 0xF0, 0x16, -1} }, { {0xe0, 0xf0, 0x12, -1}, {0xe0, 0x12, -1} }, /*100*/ + { {-1}, {-1} }, { {0xe0, 0x25, -1}, {0xe0, 0xF0, 0x25, -1} }, { {0xe0, 0x2E, -1}, {0xe0, 0xF0, 0x2E, -1} }, { {0xe0, 0x36, -1}, {0xe0, 0xF0, 0x36, -1} }, /*104*/ + { {0xe0, 0x19, -1}, {0xe0, 0xF0, 0x19, -1} }, { {0xe0, 0x39, -1}, {0xe0, 0xF0, 0x39, -1} }, { {0xe0, 0x6E, -1}, {0xe0, 0xF0, 0x6E, -1} }, { {0xe0, 0xe1, -1}, {0xe0, 0xF0, 0xE1, -1} }, /*108*/ + { {0xe0, 0xee, -1}, {0xe0, 0xF0, 0xEE, -1} }, { {0xe0, 0xf1, -1}, {0xe0, 0xF0, 0xF1, -1} }, { {0xe0, 0xfe, -1}, {0xe0, 0xF0, 0xFE, -1} }, { {0xe0, 0xff, -1}, {0xe0, 0xF0, 0xFF, -1} } /*10c*/ +}; + +static scancode scancode_set3[272] = +{ + { {-1}, {-1} }, { {0x08, -1}, {0xF0, 0x08, -1} }, { {0x16, -1}, {0xF0, 0x16, -1} }, { {0x1E, -1}, {0xF0, 0x1E, -1} }, + { {0x26, -1}, {0xF0, 0x26, -1} }, { {0x25, -1}, {0xF0, 0x25, -1} }, { {0x2E, -1}, {0xF0, 0x2E, -1} }, { {0x36, -1}, {0xF0, 0x36, -1} }, + { {0x3D, -1}, {0xF0, 0x3D, -1} }, { {0x3E, -1}, {0xF0, 0x3E, -1} }, { {0x46, -1}, {0xF0, 0x46, -1} }, { {0x45, -1}, {0xF0, 0x45, -1} }, + { {0x4E, -1}, {0xF0, 0x4E, -1} }, { {0x55, -1}, {0xF0, 0x55, -1} }, { {0x66, -1}, {0xF0, 0x66, -1} }, { {0x0D, -1}, {0xF0, 0x0D, -1} }, + { {0x15, -1}, {0xF0, 0x15, -1} }, { {0x1D, -1}, {0xF0, 0x1D, -1} }, { {0x24, -1}, {0xF0, 0x24, -1} }, { {0x2D, -1}, {0xF0, 0x2D, -1} }, + { {0x2C, -1}, {0xF0, 0x2C, -1} }, { {0x35, -1}, {0xF0, 0x35, -1} }, { {0x3C, -1}, {0xF0, 0x3C, -1} }, { {0x43, -1}, {0xF0, 0x43, -1} }, + { {0x44, -1}, {0xF0, 0x44, -1} }, { {0x4D, -1}, {0xF0, 0x4D, -1} }, { {0x54, -1}, {0xF0, 0x54, -1} }, { {0x5B, -1}, {0xF0, 0x5B, -1} }, + { {0x5A, -1}, {0xF0, 0x5A, -1} }, { {0x11, -1}, {0xF0, 0x11, -1} }, { {0x1C, -1}, {0xF0, 0x1C, -1} }, { {0x1B, -1}, {0xF0, 0x1B, -1} }, + { {0x23, -1}, {0xF0, 0x23, -1} }, { {0x2B, -1}, {0xF0, 0x2B, -1} }, { {0x34, -1}, {0xF0, 0x34, -1} }, { {0x33, -1}, {0xF0, 0x33, -1} }, + { {0x3B, -1}, {0xF0, 0x3B, -1} }, { {0x42, -1}, {0xF0, 0x42, -1} }, { {0x4B, -1}, {0xF0, 0x4B, -1} }, { {0x4C, -1}, {0xF0, 0x4C, -1} }, + { {0x52, -1}, {0xF0, 0x52, -1} }, { {0x0E, -1}, {0xF0, 0x0E, -1} }, { {0x12, -1}, {0xF0, 0x12, -1} }, { {0x5D, -1}, {0xF0, 0x5D, -1} }, + { {0x1A, -1}, {0xF0, 0x1A, -1} }, { {0x22, -1}, {0xF0, 0x22, -1} }, { {0x21, -1}, {0xF0, 0x21, -1} }, { {0x2A, -1}, {0xF0, 0x2A, -1} }, + { {0x32, -1}, {0xF0, 0x32, -1} }, { {0x31, -1}, {0xF0, 0x31, -1} }, { {0x3A, -1}, {0xF0, 0x3A, -1} }, { {0x41, -1}, {0xF0, 0x41, -1} }, + { {0x49, -1}, {0xF0, 0x49, -1} }, { {0x4A, -1}, {0xF0, 0x4A, -1} }, { {0x59, -1}, {0xF0, 0x59, -1} }, { {0x7E, -1}, {0xF0, 0x7E, -1} }, + { {0x19, -1}, {0xF0, 0x19, -1} }, { {0x29, -1}, {0xF0, 0x29, -1} }, { {0x14, -1}, {0xF0, 0x14, -1} }, { {0x07, -1}, {0xF0, 0x07, -1} }, + { {0x0F, -1}, {0xF0, 0x0F, -1} }, { {0x17, -1}, {0xF0, 0x17, -1} }, { {0x1F, -1}, {0xF0, 0x1F, -1} }, { {0x27, -1}, {0xF0, 0x27, -1} }, + { {0x2F, -1}, {0xF0, 0x2F, -1} }, { {0x37, -1}, {0xF0, 0x37, -1} }, { {0x3F, -1}, {0xF0, 0x3F, -1} }, { {0x47, -1}, {0xF0, 0x47, -1} }, + { {0x4F, -1}, {0xF0, 0x4F, -1} }, { {0x76, -1}, {0xF0, 0x76, -1} }, { {0x5F, -1}, {0xF0, 0x5F, -1} }, { {0x6C, -1}, {0xF0, 0x6C, -1} }, + { {0x75, -1}, {0xF0, 0x75, -1} }, { {0x7D, -1}, {0xF0, 0x7D, -1} }, { {0x84, -1}, {0xF0, 0x84, -1} }, { {0x6B, -1}, {0xF0, 0x6B, -1} }, + { {0x73, -1}, {0xF0, 0x73, -1} }, { {0x74, -1}, {0xF0, 0x74, -1} }, { {0x7C, -1}, {0xF0, 0x7C, -1} }, { {0x69, -1}, {0xF0, 0x69, -1} }, + { {0x72, -1}, {0xF0, 0x72, -1} }, { {0x7A, -1}, {0xF0, 0x7A, -1} }, { {0x70, -1}, {0xF0, 0x70, -1} }, { {0x71, -1}, {0xF0, 0x71, -1} }, + { {0x57, -1}, {0xF0, 0x57, -1} }, { {0x60, -1}, {0xF0, 0x60, -1} }, { {-1}, {-1} }, { {0x56, -1}, {0xF0, 0x56, -1} }, + { {0x5E, -1}, {0xF0, 0x5E, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {0x10, -1}, {0xF0, 0x10, -1} }, { {0x18, -1}, {0xF0, 0x18, -1} }, { {0x20, -1}, {0xF0, 0x20, -1} }, + { {0x28, -1}, {0xF0, 0x28, -1} }, { {0x30, -1}, {0xF0, 0x30, -1} }, { {0x38, -1}, {0xF0, 0x38, -1} }, { {0x40, -1}, {0xF0, 0x40, -1} }, + { {0x48, -1}, {0xF0, 0x48, -1} }, { {0x50, -1}, {0xF0, 0x50, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, + { {0x87, -1}, {0xF0, 0x87, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {0x51, -1}, {0xF0, 0x51, -1} }, + { {0x53, -1}, {0xF0, 0x53, -1} }, { {0x5C, -1}, {0xF0, 0x5C, -1} }, { {-1}, {-1} }, { {0x62, -1}, {0xF0, 0x62, -1} }, + { {0x63, -1}, {0xF0, 0x63, -1} }, { {0x86, -1}, {0xF0, 0x86, -1} }, { {-1}, {-1} }, { {0x85, -1}, {0xF0, 0x85, -1} }, + { {0x68, -1}, {0xF0, 0x68, -1} }, { {0x13, -1}, {0xF0, 0x13, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, + + { {0x80, -1}, {0xF0, 0x80, -1} }, { {0x81, -1}, {0xF0, 0x81, -1} }, { {0x82, -1}, {0xF0, 0x82, -1} }, { {0xe0, 0x1E, -1}, {0xe0, 0xF0, 0x1E, -1} }, /*80*/ + { {0xe0, 0x26, -1}, {0xe0, 0xF0, 0x26, -1} }, { {0x85, -1}, {0xF0, 0x85, -1} }, { {0x86, -1}, {0xF0, 0x86, -1} }, { {0x87, -1}, {0xF0, 0x87, -1} }, /*84*/ + { {0xe0, 0x3D, -1}, {0xe0, 0xF0, 0x3D, -1} }, { {0xe0, 0x3E, -1}, {0xe0, 0xF0, 0x3E, -1} }, { {0xe0, 0x46, -1}, {0xe0, 0xF0, 0x46, -1} }, { {0xe0, 0x45, -1}, {0xe0, 0xF0, 0x45, -1} }, /*88*/ + { {0xe0, 0x4E, -1}, {0xe0, 0xF0, 0x4E, -1} }, { {-1}, {-1} }, { {0xe0, 0x66, -1}, {0xe0, 0xF0, 0x66, -1} }, { {0xe0, 0x0D, -1}, {0xe0, 0xF0, 0x0D, -1} }, /*8c*/ + { {0xe0, 0x15, -1}, {0xe0, 0xF0, 0x15, -1} }, { {0xe0, 0x1D, -1}, {0xe0, 0xF0, 0x1D, -1} }, { {0xe0, 0x24, -1}, {0xe0, 0xF0, 0x24, -1} }, { {0xe0, 0x2D, -1}, {0xe0, 0xF0, 0x2D, -1} }, /*90*/ + { {0xe0, 0x2C, -1}, {0xe0, 0xF0, 0x2C, -1} }, { {0xe0, 0x35, -1}, {0xe0, 0xF0, 0x35, -1} }, { {0xe0, 0x3C, -1}, {0xe0, 0xF0, 0x3C, -1} }, { {0xe0, 0x43, -1}, {0xe0, 0xF0, 0x43, -1} }, /*94*/ + { {0xe0, 0x44, -1}, {0xe0, 0xF0, 0x44, -1} }, { {0xe0, 0x4D, -1}, {0xe0, 0xF0, 0x4D, -1} }, { {0xe0, 0x54, -1}, {0xe0, 0xF0, 0x54, -1} }, { {0xe0, 0x5B, -1}, {0xe0, 0xF0, 0x5B, -1} }, /*98*/ + { {0x79, -1}, {0xF0, 0x79, -1} }, { {0x58, -1}, {0xF0, 0x58, -1} }, { {0xe0, 0x1C, -1}, {0xe0, 0xF0, 0x1C, -1} }, { {0xe0, 0x1B, -1}, {0xe0, 0xF0, 0x1B, -1} }, /*9c*/ + { {0xe0, 0x23, -1}, {0xe0, 0xF0, 0x23, -1} }, { {0xe0, 0x2B, -1}, {0xe0, 0xF0, 0x2B, -1} }, { {0xe0, 0x34, -1}, {0xe0, 0xF0, 0x34, -1} }, { {0xe0, 0x33, -1}, {0xe0, 0xF0, 0x33, -1} }, /*a0*/ + { {0xe0, 0x3B, -1}, {0xe0, 0xF0, 0x3B, -1} }, { {0xe0, 0x42, -1}, {0xe0, 0xF0, 0x42, -1} }, { {0xe0, 0x4B, -1}, {0xe0, 0xF0, 0x4B, -1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a8*/ + { {0xe0, 0x1A, -1}, {0xe0, 0xF0, 0x1A, -1} }, { {0xe0, 0x22, -1}, {0xe0, 0xF0, 0x22, -1} }, { {0xe0, 0x21, -1}, {0xe0, 0xF0, 0x21, -1} }, { {0xe0, 0x2A, -1}, {0xe0, 0xF0, 0x2A, -1} }, /*ac*/ + { {0xe0, 0x32, -1}, {0xe0, 0xF0, 0x32, -1} }, { {0xe0, 0x31, -1}, {0xe0, 0xF0, 0x31, -1} }, { {0xe0, 0x3A, -1}, {0xe0, 0xF0, 0x3A, -1} }, { {-1}, {-1} }, /*b0*/ + { {0xe0, 0x49, -1}, {0xe0, 0xF0, 0x49, -1} }, { {0x77, -1}, {0xF0, 0x77, -1} }, { {-1}, {-1} }, { {0x57, -1}, {0xF0, 0x57, -1} }, /*b4*/ + { {0x39, -1}, {0xF0, 0x39, -1} }, { {-1}, {-1} }, { {0xe0, 0x58, -1}, {0xe0, 0xF0, 0x58, -1} }, { {0xe0, 0x05, -1}, {0xe0, 0xF0, 0x05, -1} }, /*b8*/ + { {0xe0, 0x06, -1}, {0xe0, 0xF0, 0x06, -1} }, { {0xe0, 0x04, -1}, {0xe0, 0xF0, 0x04, -1} }, { {0xe0, 0x0C, -1}, {0xe0, 0xF0, 0x0C, -1} }, { {0xe0, 0x03, -1}, {0xe0, 0xF0, 0x03, -1} }, /*bc*/ + { {0xe0, 0x0B, -1}, {0xe0, 0xF0, 0x0B, -1} }, { {0xe0, 0x02, -1}, {0xe0, 0xF0, 0x02, -1} }, { {0xe0, 0x0A, -1}, {0xe0, 0xF0, 0x0A, -1} }, { {0xe0, 0x01, -1}, {0xe0, 0xF0, 0x01, -1} }, /*c0*/ + { {0xe0, 0x09, -1}, {0xe0, 0xF0, 0x09, -1} }, { {-1}, {-1} }, { {0xe0, 0x7E, -1}, {0xe0, 0xF0, 0x7E, -1} }, { {0x6E, -1}, {0xF0, 0x6E, -1} }, /*c4*/ + { {0x63, -1}, {0xF0, 0x63, -1} }, { {0x6F, -1}, {0xF0, 0x6F, -1} }, { {-1}, {-1} }, { {0x61, -1}, {0xF0, 0x61, -1} }, /*c8*/ + { {0xe0, 0x73, -1}, {0xe0, 0xF0, 0x73, -1} }, { {0x6A, -1}, {0xF0, 0x6A, -1} }, { {0xe0, 0x79, -1}, {0xe0, 0xF0, 0x79, -1} }, { {0x65, -1}, {0xF0, 0x65, -1} }, /*cc*/ + { {0x60, -1}, {0xe0, 0x60, -1} }, { {0x6D, -1}, {0xF0, 0x6D, -1} }, { {0x67, -1}, {0xF0, 0x67, -1} }, { {0x64, -1}, {0xF0, 0x64, -1} }, /*d0*/ + { {0xd4, -1}, {0xF0, 0xD4, -1} }, { {0xe0, 0x60, -1}, {0xe0, 0xF0, 0x60, -1} }, { {-1}, {-1} }, { {0xe0, 0x78, -1}, {0xe0, 0xF0, 0x78, -1} }, /*d4*/ + { {0xe0, 0x07, -1}, {0xe0, 0xF0, 0x07, -1} }, { {0xe0, 0x0F, -1}, {0xe0, 0xF0, 0x0F, -1} }, { {0xe0, 0x17, -1}, {0xe0, 0xF0, 0x17, -1} }, { {0x8B, -1}, {0xF0, 0x8B, -1} }, /*d8*/ + { {0x8C, -1}, {0xF0, 0x8C, -1} }, { {0x8D, -1}, {0xF0, 0x8D, -1} }, { {-1}, {-1} }, { {0x7F, -1}, {0xF0, 0x7F, -1} }, /*dc*/ + { {-1}, {-1} }, { {0xe0, 0x4F, -1}, {0xe0, 0xF0, 0x4F, -1} }, { {0xe0, 0x56, -1}, {0xe0, 0xF0, 0x56, -1} }, { {-1}, {-1} }, /*e0*/ + { {0xe0, 0x08, -1}, {0xe0, 0xF0, 0x08, -1} }, { {0xe0, 0x10, -1}, {0xe0, 0xF0, 0x10, -1} }, { {0xe0, 0x18, -1}, {0xe0, 0xF0, 0x18, -1} }, { {0xe0, 0x20, -1}, {0xe0, 0xF0, 0x20, -1} }, /*e4*/ + { {0xe0, 0x28, -1}, {0xe0, 0xF0, 0x28, -1} }, { {0xe0, 0x30, -1}, {0xe0, 0xF0, 0x30, -1} }, { {0xe0, 0x38, -1}, {0xe0, 0xF0, 0x38, -1} }, { {0xe0, 0x40, -1}, {0xe0, 0xF0, 0x40, -1} }, /*e8*/ + { {0xe0, 0x48, -1}, {0xe0, 0xF0, 0x48, -1} }, { {0xe0, 0x50, -1}, {0xe0, 0xF0, 0x50, -1} }, { {0xe0, 0x57, -1}, {0xe0, 0xF0, 0x57, -1} }, { {-1}, {-1} }, /*ec*/ + { {0xe0, 0x13, -1}, {0xe0, 0xF0, 0x13, -1} }, { {0xf1, -1}, {0xF0, 0xF1, -1} }, { {0xf2, -1}, {0xF0, 0xF2, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xF0, 0x51, -1} }, /*f0*/ + { {0xe0, 0x53, -1}, {0xe0, 0xF0, 0x53, -1} }, { {0xe0, 0x5C, -1}, {0xe0, 0xF0, 0x5C, -1} }, { {-1}, {-1} }, { {0xe0, 0x62, -1}, {0xe0, 0xF0, 0x62, -1} }, /*f4*/ + { {0xe0, 0x63, -1}, {0xe0, 0xF0, 0x63, -1} }, { {0xe0, 0x64, -1}, {0xe0, 0xF0, 0x64, -1} }, { {0xe0, 0x65, -1}, {0xe0, 0xF0, 0x65, -1} }, { {0xe0, 0x67, -1}, {0xe0, 0xF0, 0x67, -1} }, /*f8*/ + { {0xe0, 0x68, -1}, {0xe0, 0xF0, 0x68, -1} }, { {0xe0, 0x6A, -1}, {0xe0, 0xF0, 0x6A, -1} }, { {0xe0, 0x6D, -1}, {0xe0, 0xF0, 0x6D, -1} }, { {0x62, -1}, {0xF0, 0x62, -1} }, /*fc*/ + + { {-1}, {-1} }, { {0xe0, 0x76, -1}, {0xe0, 0xF0, 0x76, -1} }, { {0xe0, 0x16, -1}, {0xe0, 0xF0, 0x16, -1} }, { {-1}, {-1} }, /*100*/ + { {-1}, {-1} }, { {0xe0, 0x25, -1}, {0xe0, 0xF0, 0x25, -1} }, { {0xe0, 0x2E, -1}, {0xe0, 0xF0, 0x2E, -1} }, { {0xe0, 0x36, -1}, {0xe0, 0xF0, 0x36, -1} }, /*104*/ + { {0xe0, 0x19, -1}, {0xe0, 0xF0, 0x19, -1} }, { {0xe0, 0x39, -1}, {0xe0, 0xF0, 0x39, -1} }, { {0xe0, 0x6E, -1}, {0xe0, 0xF0, 0x6E, -1} }, { {0xe0, 0xe1, -1}, {0xe0, 0xF0, 0xE1, -1} }, /*108*/ + { {0xe0, 0xee, -1}, {0xe0, 0xF0, 0xEE, -1} }, { {0xe0, 0xf1, -1}, {0xe0, 0xF0, 0xF1, -1} }, { {0xe0, 0xfe, -1}, {0xe0, 0xF0, 0xFE, -1} }, { {0xe0, 0xff, -1}, {0xe0, 0xF0, 0xFF, -1} } /*10c*/ +}; + +/*XT keyboard has no escape scancodes, and no scancodes beyond 53*/ +static scancode scancode_xt[272] = +{ + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/ + + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/ + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0xaa, -1}, {0x2a, -1} }, { {-1}, {-1} }, /*a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/ + { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0xb6, -1}, {0x36, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/ + { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/ + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*c8*/ + { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/ + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*100*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*104*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*108*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/ +}; + +/*Tandy keyboard has slightly different scancodes to XT*/ +static scancode scancode_tandy[272] = +{ + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x56, -1}, {0xd6, -1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/ + + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/ + { {0x57, -1}, {0xd7, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0xaa, -1}, {0x2a, -1} }, { {-1}, {-1} }, /*a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/ + { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0xb6, -1}, {0x36, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/ + { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/ + { {0x29, -1}, {0xa9, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x2b, -1}, {0xab, -1} }, /*c8*/ + { {-1}, {-1} }, { {0x4e, -1}, {0xce, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/ + { {0x4a, -1}, {0xca, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*100*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*104*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*108*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/ +}; +static int oldkey[272]; +static int keydelay[272]; + +/* This array acts an intermediary so scan codes are processed in the correct order (ALT-CTRL-SHIFT-RSHIFT first, then all others). */ +static int scorder[272] = {0x38, 0xB8, 0x1D, 0x9D, 0xFF, 0x2A, 0x36,0x103, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x37, 0x39, 0x3A, 0x3B, + 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, + 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, + 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, + 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, + 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, + 0x9C, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, + 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, + 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, + 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, + 0xFE,0x100,0x101,0x102,0x104,0x105,0x106,0x107,0x108,0x109,0x10A,0x10B,0x10C,0x10D,0x10E,0x10F}; + +/* bit 0 = repeat, bit 1 = makes break code? */ +int set3_flags[272]; +uint8_t set3_all_repeat = 0; +uint8_t set3_all_break = 0; + +void (*keyboard_send)(uint8_t val); +void (*keyboard_poll)(); +int keyboard_scan = 1; + +void keyboard_process() +{ + int c; + int d; + scancode *scancodes; + + if (AT) + { + switch (mode & 3) + { + case 1: + default: + scancodes = scancode_set1; + break; + case 2: + scancodes = scancode_set2; + break; + case 3: + scancodes = scancode_set3; + break; + } + if (mode & 0x20) scancodes = scancode_set1; + } + else + { + scancodes = scancode_xt; + } + + if (!keyboard_scan) return; + if (TANDY) scancodes = scancode_tandy; + + for (c = 0; c < 272; c++) + { + if (pcem_key[scorder[c]]) + keydelay[scorder[c]]++; + else + keydelay[scorder[c]] = 0; + } + + for (c = 0; c < 272; c++) + { + if (pcem_key[scorder[c]] != oldkey[scorder[c]]) + { + oldkey[scorder[c]] = pcem_key[scorder[c]]; + if ( pcem_key[scorder[c]] && scancodes[scorder[c]].scancodes_make[0] == -1) + continue; + if (!pcem_key[scorder[c]] && scancodes[scorder[c]].scancodes_break[0] == -1) + continue; + if (AT && ((mode & 3) == 3)) + { + if (!set3_all_break && !pcem_key[scorder[c]] && !(set3_flags[scancodes[scorder[c]].scancodes_make[0]] & 2)) + continue; + } +// pclog("Key %02X start\n", scorder[c]); + d = 0; + if (pcem_key[scorder[c]]) + { + while (scancodes[scorder[c]].scancodes_make[d] != -1) + keyboard_send(scancodes[scorder[c]].scancodes_make[d++]); + } + else + { + while (scancodes[scorder[c]].scancodes_break[d] != -1) + keyboard_send(scancodes[scorder[c]].scancodes_break[d++]); + } + } + } + + for (c = 0; c < 272; c++) + { + if (AT && ((mode & 3) == 3)) + { + if (scancodes[scorder[c]].scancodes_make[0] == -1) + continue; + if (!set3_all_repeat && !pcem_key[scorder[c]] && !(set3_flags[scancodes[scorder[c]].scancodes_make[0]] & 1)) + continue; + } + if (keydelay[scorder[c]] >= 30) + { + keydelay[scorder[c]] -= 10; + if (scancodes[scorder[c]].scancodes_make[0] == -1) + continue; + + d = 0; + + while (scancodes[scorder[c]].scancodes_make[d] != -1) + keyboard_send(scancodes[scorder[c]].scancodes_make[d++]); + } + } +} diff --git a/src/keyboard.h b/src/keyboard.h new file mode 100644 index 000000000..d1445b763 --- /dev/null +++ b/src/keyboard.h @@ -0,0 +1,11 @@ +extern void (*keyboard_send)(uint8_t val); +extern void (*keyboard_poll)(); +extern int keyboard_scan; + +extern int pcem_key[272]; +extern uint8_t mode; +void keyboard_process(); + +extern int set3_flags[272]; +extern uint8_t set3_all_repeat; +extern uint8_t set3_all_break; diff --git a/src/keyboard_amstrad.c b/src/keyboard_amstrad.c new file mode 100644 index 000000000..4c779ae9e --- /dev/null +++ b/src/keyboard_amstrad.c @@ -0,0 +1,178 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "pit.h" +#include "sound.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_amstrad.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int wantirq; + + uint8_t key_waiting; + uint8_t pa; + uint8_t pb; +} keyboard_amstrad; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +static uint8_t amstrad_systemstat_1, amstrad_systemstat_2; + +void keyboard_amstrad_poll() +{ + keybsenddelay += (1000 * TIMER_USEC); + if (keyboard_amstrad.wantirq) + { + keyboard_amstrad.wantirq = 0; + keyboard_amstrad.pa = keyboard_amstrad.key_waiting; + picint(2); + pclog("keyboard_amstrad : take IRQ\n"); + } + if (key_queue_start != key_queue_end && !keyboard_amstrad.pa) + { + keyboard_amstrad.key_waiting = key_queue[key_queue_start]; + pclog("Reading %02X from the key queue at %i\n", keyboard_amstrad.key_waiting, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_amstrad.wantirq = 1; + } +} + +void keyboard_amstrad_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; + pclog("keyboard_amstrad : %02X added to key queue at %i\n", val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_amstrad_write(uint16_t port, uint8_t val, void *priv) +{ + pclog("keyboard_amstrad : write %04X %02X %02X\n", port, val, keyboard_amstrad.pb); + + switch (port) + { + case 0x61: + pclog("keyboard_amstrad : pb write %02X %02X %i %02X %i\n", val, keyboard_amstrad.pb, !(keyboard_amstrad.pb & 0x40), keyboard_amstrad.pb & 0x40, (val & 0x40)); + if (!(keyboard_amstrad.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/ + { + pclog("keyboard_amstrad : reset keyboard\n"); + keyboard_amstrad_adddata(0xaa); + } + keyboard_amstrad.pb = val; + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + + if (val & 0x80) + keyboard_amstrad.pa = 0; + break; + + case 0x63: + break; + + case 0x64: + amstrad_systemstat_1 = val; + break; + + case 0x65: + amstrad_systemstat_2 = val; + break; + + default: + pclog("\nBad XT keyboard write %04X %02X\n", port, val); +// dumpregs(); +// exit(-1); + } +} + +uint8_t keyboard_amstrad_read(uint16_t port, void *priv) +{ + uint8_t temp; +// pclog("keyboard_amstrad : read %04X ", port); + switch (port) + { + case 0x60: + if (keyboard_amstrad.pb & 0x80) + { + temp = (amstrad_systemstat_1 | 0xd) & 0x7f; + } + else + { + temp = keyboard_amstrad.pa; + if (key_queue_start == key_queue_end) + { + keyboard_amstrad.wantirq = 0; + } + else + { + keyboard_amstrad.key_waiting = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_amstrad.wantirq = 1; + } + } + break; + + case 0x61: + temp = keyboard_amstrad.pb; + break; + + case 0x62: + if (keyboard_amstrad.pb & 0x04) + temp = amstrad_systemstat_2 & 0xf; + else + temp = amstrad_systemstat_2 >> 4; + temp |= (ppispeakon ? 0x20 : 0); + if (nmi) + temp |= 0x40; + break; + + default: + pclog("\nBad XT keyboard read %04X\n", port); +// dumpregs(); +// exit(-1); + } +// pclog("%02X %04X:%04X\n", temp, CS, pc); + return temp; +} + +void keyboard_amstrad_reset() +{ + keyboard_amstrad.wantirq = 0; + + keyboard_scan = 1; +} + +void keyboard_amstrad_init() +{ + //return; + pclog("keyboard_amstrad_init\n"); + io_sethandler(0x0060, 0x0006, keyboard_amstrad_read, NULL, NULL, keyboard_amstrad_write, NULL, NULL, NULL); + keyboard_amstrad_reset(); + keyboard_send = keyboard_amstrad_adddata; + keyboard_poll = keyboard_amstrad_poll; + + timer_add(keyboard_amstrad_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_amstrad.h b/src/keyboard_amstrad.h new file mode 100644 index 000000000..9d4cd15f5 --- /dev/null +++ b/src/keyboard_amstrad.h @@ -0,0 +1,3 @@ +void keyboard_amstrad_init(); +void keyboard_amstrad_reset(); +void keyboard_amstrad_poll(); diff --git a/src/keyboard_at.c b/src/keyboard_at.c new file mode 100644 index 000000000..6fd843ce4 --- /dev/null +++ b/src/keyboard_at.c @@ -0,0 +1,648 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "pit.h" +#include "sound.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_at.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_MFULL 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int initialised; + int want60; + int wantirq, wantirq12; + uint8_t command; + uint8_t status; + uint8_t mem[0x20]; + uint8_t out; + int out_new; + + uint8_t input_port; + uint8_t output_port; + + uint8_t key_command; + int key_wantdata; + + int last_irq; +} keyboard_at; + +static uint8_t key_ctrl_queue[16]; +static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +static uint8_t mouse_queue[16]; +int mouse_queue_start = 0, mouse_queue_end = 0; + +int first_write = 1; +int dtrans = 0; + +/* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ +uint8_t mode = 0x42; + +#if 0 +/* Translated to non-translated scan codes. */ + /* Assuming we get XSET1, SET1/XSET2/XSET3 = T_TO_NONT(XSET1), and then we go through + T_TO_NONT again to get SET2/SET3. */ +/* static uint8_t t_to_nont[256] = { 0xFF, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2E, 0x36, 0x3D, 0x3E, 0x46, 0x45, 0x4E, 0x55, 0x66, 0x0D, + 0x15, 0x1D, 0x24, 0x2D, 0x2C, 0x35, 0x3C, 0x43, 0x44, 0x4D, 0x54, 0x5B, 0x5A, 0x14, 0x1C, 0x1B, + 0x23, 0x2B, 0x34, 0x33, 0x3B, 0x42, 0x4B, 0x4C, 0x52, 0x0E, 0x12, 0x5D, 0x1A, 0x22, 0x21, 0x2A, + 0x32, 0x31, 0x3A, 0x41, 0x49, 0x4A, 0x59, 0x7C, 0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0C, 0x03, + 0x0B, 0x02, 0x0A, 0x01, 0x09, 0x77, 0x7E, 0x6C, 0x75, 0x7D, 0x7B, 0x6B, 0x73, 0x74, 0x79, 0x69, + 0x72, 0x7A, 0x70, 0x71, 0x7F, 0x60, 0x61, 0x78, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0x3F, + 0x47, 0x4F, 0x56, 0x5E, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6F, + 0x13, 0x19, 0x39, 0x51, 0x53, 0x5C, 0x5F, 0x62, 0x63, 0x64, 0x65, 0x67, 0x68, 0x6A, 0x6D, 0x6E, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; */ +#endif + +/* Non-translated to translated scan codes. */ +static uint8_t nont_to_t[256] = { 0xFF, 0x43, 0x41, 0x3F, 0x3D, 0x3B, 0x3C, 0x58, 0x64, 0x44, 0x42, 0x40, 0x3E, 0x0F, 0x29, 0x59, + 0x65, 0x38, 0x2A, 0x70, 0x1D, 0x10, 0x02, 0x5A, 0x66, 0x71, 0x2C, 0x1F, 0x1E, 0x11, 0x03, 0x5B, + 0x67, 0x2E, 0x2D, 0x20, 0x12, 0x05, 0x04, 0x5C, 0x68, 0x39, 0x2F, 0x21, 0x14, 0x13, 0x06, 0x5D, + 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5E, 0x6A, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5F, + 0x6B, 0x33, 0x25, 0x17, 0x18, 0x0B, 0x0A, 0x60, 0x6C, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0C, 0x61, + 0x6D, 0x73, 0x28, 0x74, 0x1A, 0x0D, 0x62, 0x6E, 0x3A, 0x36, 0x1C, 0x1B, 0x75, 0x2B, 0x63, 0x76, + 0x55, 0x56, 0x77, 0x78, 0x79, 0x7A, 0x0E, 0x7B, 0x7C, 0x4F, 0x7D, 0x4B, 0x47, 0x7E, 0x7F, 0x6F, + 0x52, 0x53, 0x50, 0x4C, 0x4D, 0x48, 0x01, 0x45, 0x57, 0x4E, 0x51, 0x4A, 0x37, 0x49, 0x46, 0x54, + 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; + +void keyboard_at_poll() +{ + keybsenddelay += (1000 * TIMER_USEC); + + if (keyboard_at.out_new != -1 && !keyboard_at.last_irq) + { + keyboard_at.wantirq = 0; + if (keyboard_at.out_new & 0x100) + { + if (keyboard_at.mem[0] & 0x02) + picint(0x1000); + keyboard_at.out = keyboard_at.out_new & 0xff; + keyboard_at.out_new = -1; + keyboard_at.status |= STAT_OFULL; + keyboard_at.status &= ~STAT_IFULL; + keyboard_at.status |= STAT_MFULL; +// pclog("keyboard_at : take IRQ12\n"); + keyboard_at.last_irq = 0x1000; + } + else + { + if (keyboard_at.mem[0] & 0x01) + picint(2); + keyboard_at.out = keyboard_at.out_new; + keyboard_at.out_new = -1; + keyboard_at.status |= STAT_OFULL; + keyboard_at.status &= ~STAT_IFULL; + keyboard_at.status &= ~STAT_MFULL; +// pclog("keyboard_at : take IRQ1\n"); + keyboard_at.last_irq = 2; + } + } + + if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && /*!(keyboard_at.mem[0] & 0x20) &&*/ + mouse_queue_start != mouse_queue_end) + { + keyboard_at.out_new = mouse_queue[mouse_queue_start] | 0x100; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } + else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && + !(keyboard_at.mem[0] & 0x10) && key_queue_start != key_queue_end) + { + keyboard_at.out_new = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + } + else if (keyboard_at.out_new == -1 && !(keyboard_at.status & STAT_OFULL) && + key_ctrl_queue_start != key_ctrl_queue_end) + { + keyboard_at.out_new = key_ctrl_queue[key_ctrl_queue_start]; + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; + } +} + +void keyboard_at_adddata(uint8_t val) +{ +// if (keyboard_at.status & STAT_OFULL) +// { + key_ctrl_queue[key_ctrl_queue_end] = val; + key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; +// pclog("keyboard_at : %02X added to queue\n", val); +/* return; + } + keyboard_at.out = val; + keyboard_at.status |= STAT_OFULL; + keyboard_at.status &= ~STAT_IFULL; + if (keyboard_at.mem[0] & 0x01) + keyboard_at.wantirq = 1; + pclog("keyboard_at : output %02X (IRQ %i)\n", val, keyboard_at.wantirq);*/ +} + +uint8_t sc_or = 0; + +void keyboard_at_adddata_keyboard(uint8_t val) +{ + /* Modification by OBattler: Allow for scan code translation. */ + if ((mode & 0x40) && (val == 0xf0) && !(mode & 0x20)) + { + sc_or = 0x80; + return; + } + /* Skip break code if translated make code has bit 7 set. */ + if ((mode & 0x40) && (sc_or == 0x80) && (nont_to_t[val] & 0x80) && !(mode & 0x20)) + { + sc_or = 0; + return; + } + key_queue[key_queue_end] = (((mode & 0x40) && !(mode & 0x20)) ? (nont_to_t[val] | sc_or) : val); + key_queue_end = (key_queue_end + 1) & 0xf; + if (sc_or == 0x80) sc_or = 0; + return; +} + +void keyboard_at_adddata_keyboard_raw(uint8_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_at_adddata_mouse(uint8_t val) +{ + mouse_queue[mouse_queue_end] = val; + mouse_queue_end = (mouse_queue_end + 1) & 0xf; +// pclog("keyboard_at : %02X added to mouse queue\n", val); + return; +} + +void keyboard_at_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("keyboard_at : write %04X %02X %i %02X\n", port, val, keyboard_at.key_wantdata, ram[8]); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x60: + if (keyboard_at.want60) + { + /*Write to controller*/ + keyboard_at.want60 = 0; + switch (keyboard_at.command) + { + case 0x40 ... 0x5f: /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + keyboard_at.command |= 0x20; + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + keyboard_at.mem[keyboard_at.command & 0x1f] = val; + if (keyboard_at.command == 0x60) + { + if ((val & 1) && (keyboard_at.status & STAT_OFULL)) + keyboard_at.wantirq = 1; + if (!(val & 1) && keyboard_at.wantirq) + keyboard_at.wantirq = 0; + mouse_scan = !(val & 0x20); + + /* Addition by OBattler: Scan code translate ON/OFF. */ + // pclog("KEYBOARD_AT: Writing %02X to system register\n", val); + mode &= 0x93; + mode |= (val & 0x6C); + if (first_write) + { + /* A bit of a hack, but it will make the keyboard behave correctly, regardless + of what the BIOS sets here. */ + mode &= 0xFC; + dtrans = mode & 0x60; + if ((mode & 0x60) == 0x40) + { + /* Bit 6 on, bit 5 off, the only case in which translation is on, + therefore, set to set 2. */ + mode |= 2; + } + first_write = 0; + // pclog("Keyboard set to scan code set %i, mode & 0x60 = 0x%02X\n", mode & 3, mode & 0x60); + /* No else because in all other cases, translation is off, so we need to keep it + set to set 0 which the mode &= 0xFC above will set it. */ + } + } + break; + + case 0xcb: /*AMI - set keyboard mode*/ + break; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ + /* To make sure the keyboard works correctly on the MegaPC. */ + mode &= 0xFC; + mode |= 2; + break; + + case 0xd1: /*Write output port*/ +// pclog("Write output port - %02X %02X %04X:%04X\n", keyboard_at.output_port, val, CS, pc); + if ((keyboard_at.output_port ^ val) & 0x02) /*A20 enable change*/ + { + mem_a20_key = val & 0x02; + mem_a20_recalc(); +// pclog("Rammask change to %08X %02X\n", rammask, val & 0x02); + flushmmucache(); + } + keyboard_at.output_port = val; + break; + + case 0xd3: /*Write to mouse output buffer*/ + keyboard_at_adddata_mouse(val); + break; + + case 0xd4: /*Write to mouse*/ + if (mouse_write) + mouse_write(val); + break; + + default: + pclog("Bad AT keyboard controller 0060 write %02X command %02X\n", val, keyboard_at.command); +// dumpregs(); +// exit(-1); + } + } + else + { + /*Write to keyboard*/ + keyboard_at.mem[0] &= ~0x10; + if (keyboard_at.key_wantdata) + { + keyboard_at.key_wantdata = 0; + switch (keyboard_at.key_command) + { + case 0xed: /*Set/reset LEDs*/ + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf0: /*Get/set scancode set*/ + // pclog("KEYBOARD_AT: Get/set scan code set: %i\n", val); + if (val == 0) + { + keyboard_at_adddata_keyboard(mode & 3); + } + else + { + if (val <= 3) + { + mode &= 0xFC; + mode |= (val & 3); + } + keyboard_at_adddata_keyboard(0xfa); + } + break; + + case 0xf3: /*Set typematic rate/delay*/ + keyboard_at_adddata_keyboard(0xfa); + break; + + default: + pclog("Bad AT keyboard 0060 write %02X command %02X\n", val, keyboard_at.key_command); +// dumpregs(); +// exit(-1); + } + } + else + { + keyboard_at.key_command = val; + switch (val) + { + case 0x00: + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + keyboard_at_adddata_keyboard(0xfe); + break; + + case 0xed: /*Set/reset LEDs*/ + keyboard_at.key_wantdata = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf0: /*Get/set scan code set*/ + keyboard_at.key_wantdata = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf2: /*Read ID*/ + /* Fixed as translation will be done in keyboard_at_adddata_keyboard(). */ + keyboard_at_adddata_keyboard(0xfa); + keyboard_at_adddata_keyboard(0xab); + keyboard_at_adddata_keyboard(0x83); + break; + + case 0xf3: /*Set typematic rate/delay*/ + keyboard_at.key_wantdata = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf4: /*Enable keyboard*/ + keyboard_scan = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + case 0xf5: /*Disable keyboard*/ + keyboard_scan = 0; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf6: /*Set defaults*/ + // pclog("KEYBOARD_AT: Set defaults\n"); + set3_all_break = 0; + set3_all_repeat = 0; + memset(set3_flags, 0, 272); + mode = (mode & 0xFC) | 2; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf7: /*Set all keys to repeat*/ + set3_all_break = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf8: /*Set all keys to give make/break codes*/ + set3_all_break = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf9: /*Set all keys to give make codes only*/ + set3_all_break = 0; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xfa: /*Set all keys to repeat and give make/break codes*/ + set3_all_repeat = 1; + set3_all_break = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xff: /*Reset*/ + // pclog("KEYBOARD_AT: Set defaults\n"); + key_queue_start = key_queue_end = 0; /*Clear key queue*/ + keyboard_at_adddata_keyboard(0xfa); + keyboard_at_adddata_keyboard(0xaa); + /* Set system flag to 1 and scan code set to 2. */ + mode &= 0xFC; + mode |= 2; + break; + + default: + pclog("Bad AT keyboard command %02X\n", val); + keyboard_at_adddata_keyboard(0xfe); +// dumpregs(); +// exit(-1); + } + } + } + break; + + case 0x61: + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + break; + + case 0x64: + keyboard_at.want60 = 0; + keyboard_at.command = val; + /*New controller command*/ + switch (val) + { + case 0x00 ... 0x1f: + val |= 0x20; /* 0x00-0x1f are aliases for 0x20-0x3f */ + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + keyboard_at_adddata(keyboard_at.mem[val & 0x1f]); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + keyboard_at.want60 = 1; + break; + + case 0xa1: /*AMI - get controlled version*/ + break; + + case 0xa7: /*Disable mouse port*/ + mouse_scan = 0; + break; + + case 0xa8: /*Enable mouse port*/ + mouse_scan = 1; + break; + + case 0xa9: /*Test mouse port*/ + keyboard_at_adddata(0x00); /*no error*/ + break; + + case 0xaa: /*Self-test*/ + if (!keyboard_at.initialised) + { + keyboard_at.initialised = 1; + key_ctrl_queue_start = key_ctrl_queue_end = 0; + keyboard_at.status &= ~STAT_OFULL; + } + keyboard_at.status |= STAT_SYSFLAG; + keyboard_at.mem[0] |= 0x04; + keyboard_at_adddata(0x55); + /*Self-test also resets the output port, enabling A20*/ + if (!(keyboard_at.output_port & 0x02)) + { + mem_a20_key = 2; + mem_a20_recalc(); +// pclog("Rammask change to %08X %02X\n", rammask, val & 0x02); + flushmmucache(); + } + keyboard_at.output_port = 0xcf; + break; + + case 0xab: /*Interface test*/ + keyboard_at_adddata(0x00); /*no error*/ + break; + + case 0xad: /*Disable keyboard*/ + keyboard_at.mem[0] |= 0x10; + break; + + case 0xae: /*Enable keyboard*/ + keyboard_at.mem[0] &= ~0x10; + break; + + case 0xc0: /*Read input port*/ + keyboard_at_adddata(keyboard_at.input_port | 4); + keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc); + break; + + case 0xc9: /*AMI - block P22 and P23 ??? */ + break; + + case 0xca: /*AMI - read keyboard mode*/ + keyboard_at_adddata(0x00); /*ISA mode*/ + break; + + case 0xcb: /*AMI - set keyboard mode*/ + keyboard_at.want60 = 1; + break; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ + keyboard_at.want60 = 1; + break; + + case 0xd0: /*Read output port*/ + keyboard_at_adddata(keyboard_at.output_port); + break; + + case 0xd1: /*Write output port*/ + keyboard_at.want60 = 1; + break; + + case 0xd3: /*Write mouse output buffer*/ + keyboard_at.want60 = 1; + break; + + case 0xd4: /*Write to mouse*/ + keyboard_at.want60 = 1; + break; + + case 0xe0: /*Read test inputs*/ + keyboard_at_adddata(0x00); + break; + + case 0xef: /*??? - sent by AMI486*/ + break; + + case 0xfe: /*Pulse output port - pin 0 selected - x86 reset*/ + softresetx86(); /*Pulse reset!*/ + break; + + case 0xff: /*Pulse output port - but no pins selected - sent by MegaPC BIOS*/ + break; + + default: + pclog("Bad AT keyboard controller command %02X\n", val); +// dumpregs(); +// exit(-1); + } + } +} + +uint8_t keyboard_at_read(uint16_t port, void *priv) +{ + uint8_t temp = 0xff; + cycles -= 4; +// if (port != 0x61) pclog("keyboard_at : read %04X ", port); + switch (port) + { + case 0x60: + temp = keyboard_at.out; + keyboard_at.status &= ~(STAT_OFULL/* | STAT_MFULL*/); + picintc(keyboard_at.last_irq); + keyboard_at.last_irq = 0; + break; + + case 0x61: + if (ppispeakon) return (ppi.pb&~0xC0)|0x20; + return ppi.pb&~0xe0; + + case 0x64: + temp = keyboard_at.status; + temp &= 0xEB; + temp |= (mode & 4); + if (mode & 8) temp |= STAT_LOCK; + keyboard_at.status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + break; + } +// if (port != 0x61) pclog("%02X %08X\n", temp, rammask); + return temp; +} + +void keyboard_at_reset() +{ + keyboard_at.initialised = 0; + keyboard_at.status = STAT_LOCK | STAT_CD; + keyboard_at.mem[0] = 0x11; + mode = 0x02 | dtrans; + first_write = 1; + keyboard_at.wantirq = 0; + keyboard_at.output_port = 0xcf; + keyboard_at.input_port = 0xb0; + keyboard_at.out_new = -1; + keyboard_at.last_irq = 0; + + keyboard_at.key_wantdata = 0; + + keyboard_scan = 1; + + sc_or = 0; + + memset(set3_flags, 0, 272); +} + +void keyboard_at_init() +{ + //return; + io_sethandler(0x0060, 0x0005, keyboard_at_read, NULL, NULL, keyboard_at_write, NULL, NULL, NULL); + keyboard_at_reset(); + keyboard_send = keyboard_at_adddata_keyboard; + keyboard_poll = keyboard_at_poll; + mouse_write = NULL; + dtrans = 0; + + timer_add(keyboard_at_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_at.h b/src/keyboard_at.h new file mode 100644 index 000000000..2493e8187 --- /dev/null +++ b/src/keyboard_at.h @@ -0,0 +1,8 @@ +void keyboard_at_init(); +void keyboard_at_reset(); +void keyboard_at_poll(); +void keyboard_at_adddata_keyboard_raw(uint8_t val); + +void (*mouse_write)(uint8_t val); +extern int mouse_queue_start, mouse_queue_end; +extern int mouse_scan; diff --git a/src/keyboard_olim24.c b/src/keyboard_olim24.c new file mode 100644 index 000000000..f20a63912 --- /dev/null +++ b/src/keyboard_olim24.c @@ -0,0 +1,309 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "mouse.h" +#include "pic.h" +#include "sound.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_olim24.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int wantirq; + uint8_t command; + uint8_t status; + uint8_t out; + + uint8_t output_port; + + int param, param_total; + uint8_t params[16]; + + int mouse_mode; +} keyboard_olim24; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +static uint8_t mouse_scancodes[7]; + +void keyboard_olim24_poll() +{ + keybsenddelay += (1000 * TIMER_USEC); + //pclog("poll %i\n", keyboard_olim24.wantirq); + if (keyboard_olim24.wantirq) + { + keyboard_olim24.wantirq = 0; + picint(2); + pclog("keyboard_olim24 : take IRQ\n"); + } + if (!(keyboard_olim24.status & STAT_OFULL) && key_queue_start != key_queue_end) + { + pclog("Reading %02X from the key queue at %i\n", keyboard_olim24.out, key_queue_start); + keyboard_olim24.out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_olim24.status |= STAT_OFULL; + keyboard_olim24.status &= ~STAT_IFULL; + keyboard_olim24.wantirq = 1; + } +} + +void keyboard_olim24_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; + pclog("keyboard_olim24 : %02X added to key queue %02X\n", val, keyboard_olim24.status); + return; +} + +void keyboard_olim24_write(uint16_t port, uint8_t val, void *priv) +{ + pclog("keyboard_olim24 : write %04X %02X\n", port, val); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x60: + if (keyboard_olim24.param != keyboard_olim24.param_total) + { + keyboard_olim24.params[keyboard_olim24.param++] = val; + if (keyboard_olim24.param == keyboard_olim24.param_total) + { + switch (keyboard_olim24.command) + { + case 0x11: + keyboard_olim24.mouse_mode = 0; + mouse_scancodes[0] = keyboard_olim24.params[0]; + mouse_scancodes[1] = keyboard_olim24.params[1]; + mouse_scancodes[2] = keyboard_olim24.params[2]; + mouse_scancodes[3] = keyboard_olim24.params[3]; + mouse_scancodes[4] = keyboard_olim24.params[4]; + mouse_scancodes[5] = keyboard_olim24.params[5]; + mouse_scancodes[6] = keyboard_olim24.params[6]; + break; + + case 0x12: + keyboard_olim24.mouse_mode = 1; + mouse_scancodes[0] = keyboard_olim24.params[0]; + mouse_scancodes[1] = keyboard_olim24.params[1]; + mouse_scancodes[2] = keyboard_olim24.params[2]; + break; + + default: + pclog("Bad keyboard command complete %02X\n", keyboard_olim24.command); +// dumpregs(); +// exit(-1); + } + } + } + else + { + keyboard_olim24.command = val; + switch (val) + { + case 0x01: /*Self-test*/ + break; + + case 0x05: /*Read ID*/ + keyboard_olim24_adddata(0x00); + break; + + case 0x11: + keyboard_olim24.param = 0; + keyboard_olim24.param_total = 9; + break; + + case 0x12: + keyboard_olim24.param = 0; + keyboard_olim24.param_total = 4; + break; + + default: + pclog("Bad keyboard command %02X\n", val); +// dumpregs(); +// exit(-1); + } + } + + break; + + case 0x61: + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + break; + } +} + +uint8_t keyboard_olim24_read(uint16_t port, void *priv) +{ + uint8_t temp; +// pclog("keyboard_olim24 : read %04X ", port); + switch (port) + { + case 0x60: + temp = keyboard_olim24.out; + if (key_queue_start == key_queue_end) + { + keyboard_olim24.status &= ~STAT_OFULL; + keyboard_olim24.wantirq = 0; + } + else + { + keyboard_olim24.out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_olim24.status |= STAT_OFULL; + keyboard_olim24.status &= ~STAT_IFULL; + keyboard_olim24.wantirq = 1; + } + break; + + case 0x61: + return ppi.pb; + + case 0x64: + temp = keyboard_olim24.status; + keyboard_olim24.status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT); + break; + + default: + pclog("\nBad olim24 keyboard read %04X\n", port); +// dumpregs(); +// exit(-1); + } +// pclog("%02X\n", temp); + return temp; +} + +void keyboard_olim24_reset() +{ + keyboard_olim24.status = STAT_LOCK | STAT_CD; + keyboard_olim24.wantirq = 0; + + keyboard_scan = 1; + + keyboard_olim24.param = keyboard_olim24.param_total = 0; + + keyboard_olim24.mouse_mode = 0; + mouse_scancodes[0] = 0x1c; + mouse_scancodes[1] = 0x53; + mouse_scancodes[2] = 0x01; + mouse_scancodes[3] = 0x4b; + mouse_scancodes[4] = 0x4d; + mouse_scancodes[5] = 0x48; + mouse_scancodes[6] = 0x50; +} + +static int mouse_x = 0, mouse_y = 0, mouse_b = 0; +void mouse_olim24_poll(int x, int y, int b) +{ + mouse_x += x; + mouse_y += y; + + pclog("mouse_poll - %i, %i %i, %i\n", x, y, mouse_x, mouse_y); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + if ((b & 1) && !(mouse_b & 1)) + keyboard_olim24_adddata(mouse_scancodes[0]); + if (!(b & 1) && (mouse_b & 1)) + keyboard_olim24_adddata(mouse_scancodes[0] | 0x80); + mouse_b = (mouse_b & ~1) | (b & 1); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + if ((b & 2) && !(mouse_b & 2)) + keyboard_olim24_adddata(mouse_scancodes[2]); + if (!(b & 2) && (mouse_b & 2)) + keyboard_olim24_adddata(mouse_scancodes[2] | 0x80); + mouse_b = (mouse_b & ~2) | (b & 2); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + if ((b & 4) && !(mouse_b & 4)) + keyboard_olim24_adddata(mouse_scancodes[1]); + if (!(b & 4) && (mouse_b & 4)) + keyboard_olim24_adddata(mouse_scancodes[1] | 0x80); + mouse_b = (mouse_b & ~4) | (b & 4); + + if (keyboard_olim24.mouse_mode) + { + if (((key_queue_end - key_queue_start) & 0xf) > 12) return; + if (!mouse_x && !mouse_y) return; + + mouse_y = -mouse_y; + + if (mouse_x < -127) mouse_x = -127; + if (mouse_x > 127) mouse_x = 127; + if (mouse_x < -127) mouse_x = 0x80 | ((-mouse_x) & 0x7f); + + if (mouse_y < -127) mouse_y = -127; + if (mouse_y > 127) mouse_y = 127; + if (mouse_y < -127) mouse_y = 0x80 | ((-mouse_y) & 0x7f); + + keyboard_olim24_adddata(0xfe); + keyboard_olim24_adddata(mouse_x); + keyboard_olim24_adddata(mouse_y); + + mouse_x = mouse_y = 0; + } + else + { + while (mouse_x < -4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_x+=4; + keyboard_olim24_adddata(mouse_scancodes[3]); + } + while (mouse_x > 4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_x-=4; + keyboard_olim24_adddata(mouse_scancodes[4]); + } + while (mouse_y < -4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_y+=4; + keyboard_olim24_adddata(mouse_scancodes[5]); + } + while (mouse_y > 4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_y-=4; + keyboard_olim24_adddata(mouse_scancodes[6]); + } + } +} + +void keyboard_olim24_init() +{ + //return; + io_sethandler(0x0060, 0x0002, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL, NULL); + io_sethandler(0x0064, 0x0001, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL, NULL); + keyboard_olim24_reset(); + keyboard_send = keyboard_olim24_adddata; + keyboard_poll = keyboard_olim24_poll; + mouse_poll = mouse_olim24_poll; + + timer_add(keyboard_olim24_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_olim24.h b/src/keyboard_olim24.h new file mode 100644 index 000000000..305a3e245 --- /dev/null +++ b/src/keyboard_olim24.h @@ -0,0 +1,3 @@ +void keyboard_olim24_init(); +void keyboard_olim24_reset(); +void keyboard_olim24_poll(); diff --git a/src/keyboard_pcjr.c b/src/keyboard_pcjr.c new file mode 100644 index 000000000..b041a5b06 --- /dev/null +++ b/src/keyboard_pcjr.c @@ -0,0 +1,208 @@ +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "nmi.h" +#include "pic.h" +#include "sound.h" +#include "sound_sn76489.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_pcjr.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int latched; + int data; + + int serial_data[44]; + int serial_pos; + + uint8_t pa; + uint8_t pb; +} keyboard_pcjr; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +void keyboard_pcjr_poll() +{ + keybsenddelay += (220 * TIMER_USEC); + + + if (key_queue_start != key_queue_end && !keyboard_pcjr.serial_pos && !keyboard_pcjr.latched) + { + int c; + int p = 0; + uint8_t key = key_queue[key_queue_start]; + +// pclog("Reading %02X from the key queue at %i\n", key, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + + keyboard_pcjr.latched = 1; + + keyboard_pcjr.serial_data[0] = 1; /*Start bit*/ + keyboard_pcjr.serial_data[1] = 0; + + for (c = 0; c < 8; c++) + { + if (key & (1 << c)) + { + keyboard_pcjr.serial_data[(c + 1) * 2] = 1; + keyboard_pcjr.serial_data[(c + 1) * 2 + 1] = 0; + p++; + } + else + { + keyboard_pcjr.serial_data[(c + 1) * 2] = 0; + keyboard_pcjr.serial_data[(c + 1) * 2 + 1] = 1; + } + } + + if (p & 1) /*Parity*/ + { + keyboard_pcjr.serial_data[9 * 2] = 1; + keyboard_pcjr.serial_data[9 * 2 + 1] = 0; + } + else + { + keyboard_pcjr.serial_data[9 * 2] = 0; + keyboard_pcjr.serial_data[9 * 2 + 1] = 1; + } + + for (c = 0; c < 11; c++) /*11 stop bits*/ + { + keyboard_pcjr.serial_data[(c + 10) * 2] = 0; + keyboard_pcjr.serial_data[(c + 10) * 2 + 1] = 0; + } + + keyboard_pcjr.serial_pos++; + } + + if (keyboard_pcjr.serial_pos) + { + keyboard_pcjr.data = keyboard_pcjr.serial_data[keyboard_pcjr.serial_pos - 1]; + nmi = keyboard_pcjr.data; + keyboard_pcjr.serial_pos++; + if (keyboard_pcjr.serial_pos == 42+1) + keyboard_pcjr.serial_pos = 0; +// pclog("Keyboard poll %i %i\n", keyboard_pcjr.data, keyboard_pcjr.serial_pos); + } +} + +void keyboard_pcjr_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; +// pclog("keyboard_pcjr : %02X added to key queue at %i\n", val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_pcjr_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("keyboard_pcjr : write %04X %02X %02X\n", port, val, keyboard_pcjr.pb); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x60: + keyboard_pcjr.pa = val; + break; + + case 0x61: + keyboard_pcjr.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + sn76489_mute = speaker_mute = 1; + switch (val & 0x60) + { + case 0x00: + speaker_mute = 0; + break; + case 0x60: + sn76489_mute = 0; + break; + } + break; + + case 0xa0: + nmi_mask = val & 0x80; + pit_set_using_timer(1, !(val & 0x20)); + break; + } +} + +uint8_t keyboard_pcjr_read(uint16_t port, void *priv) +{ + uint8_t temp; +// pclog("keyboard_pcjr : read %04X ", port); + switch (port) + { + case 0x60: + temp = keyboard_pcjr.pa; + break; + + case 0x61: + temp = keyboard_pcjr.pb; + break; + + case 0x62: + temp = (keyboard_pcjr.latched ? 1 : 0); + temp |= 0x02; /*Modem card not installed*/ + temp |= (ppispeakon ? 0x10 : 0); + temp |= (ppispeakon ? 0x20 : 0); + temp |= (keyboard_pcjr.data ? 0x40: 0); +// temp |= 0x04; + if (keyboard_pcjr.data) + temp |= 0x40; + break; + + case 0xa0: + keyboard_pcjr.latched = 0; + break; + + default: + pclog("\nBad XT keyboard read %04X\n", port); + //dumpregs(); + //exit(-1); + } +// pclog("%02X\n", temp); + return temp; +} + +void keyboard_pcjr_reset() +{ +} + +void keyboard_pcjr_init() +{ + //return; + io_sethandler(0x0060, 0x0004, keyboard_pcjr_read, NULL, NULL, keyboard_pcjr_write, NULL, NULL, NULL); + io_sethandler(0x00a0, 0x0008, keyboard_pcjr_read, NULL, NULL, keyboard_pcjr_write, NULL, NULL, NULL); + keyboard_pcjr_reset(); + keyboard_send = keyboard_pcjr_adddata; + keyboard_poll = keyboard_pcjr_poll; + + timer_add(keyboard_pcjr_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_pcjr.h b/src/keyboard_pcjr.h new file mode 100644 index 000000000..ef585ecfa --- /dev/null +++ b/src/keyboard_pcjr.h @@ -0,0 +1,3 @@ +void keyboard_pcjr_init(); +void keyboard_pcjr_reset(); +void keyboard_pcjr_poll(); diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c new file mode 100644 index 000000000..96f731c56 --- /dev/null +++ b/src/keyboard_xt.c @@ -0,0 +1,184 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "sound.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_xt.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int blocked; + + uint8_t pa; + uint8_t pb; + + int tandy; +} keyboard_xt; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +void keyboard_xt_poll() +{ + keybsenddelay += (1000 * TIMER_USEC); + if (key_queue_start != key_queue_end && !keyboard_xt.blocked) + { + keyboard_xt.pa = key_queue[key_queue_start]; + picint(2); + pclog("Reading %02X from the key queue at %i\n", keyboard_xt.pa, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_xt.blocked = 1; + } +} + +void keyboard_xt_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; + pclog("keyboard_xt : %02X added to key queue at %i\n", val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_xt_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("keyboard_xt : write %04X %02X %02X\n", port, val, keyboard_xt.pb); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x61: +// pclog("keyboard_xt : pb write %02X %02X %i %02X %i\n", val, keyboard_xt.pb, !(keyboard_xt.pb & 0x40), keyboard_xt.pb & 0x40, (val & 0x40)); + if (!(keyboard_xt.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/ + { + pclog("keyboard_xt : reset keyboard\n"); + key_queue_end = key_queue_start; + keyboard_xt_adddata(0xaa); + } + if ((keyboard_xt.pb & 0x80)==0 && (val & 0x80)!=0) + { + keyboard_xt.pa = 0; + keyboard_xt.blocked = 0; + picintc(2); + } + keyboard_xt.pb = val; + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + + break; + } +} + +uint8_t keyboard_xt_read(uint16_t port, void *priv) +{ + uint8_t temp; +// pclog("keyboard_xt : read %04X ", port); + switch (port) + { + case 0x60: + if ((romset == ROM_IBMPC) && (keyboard_xt.pb & 0x80)) + { + if (VGA || gfxcard == GFX_EGA) + temp = 0x4D; + else if (MDA) + temp = 0x7D; + else + temp = 0x6D; + } + else + temp = keyboard_xt.pa; + break; + + case 0x61: + temp = keyboard_xt.pb; + break; + + case 0x62: + if (romset == ROM_IBMPC) + { + if (keyboard_xt.pb & 0x04) + temp = 0x02; + else + temp = 0x01; + } + else + { + if (keyboard_xt.pb & 0x08) + { + if (VGA || gfxcard == GFX_EGA) + temp = 4; + else if (MDA) + temp = 7; + else + temp = 6; + } + else + temp = 0xD; + } + temp |= (ppispeakon ? 0x20 : 0); + if (keyboard_xt.tandy) + temp |= (tandy_eeprom_read() ? 0x10 : 0); + break; + + default: + pclog("\nBad XT keyboard read %04X\n", port); + //dumpregs(); + //exit(-1); + } +// pclog("%02X\n", temp); + return temp; +} + +void keyboard_xt_reset() +{ + keyboard_xt.blocked = 0; + + keyboard_scan = 1; +} + +void keyboard_xt_init() +{ + //return; + io_sethandler(0x0060, 0x0004, keyboard_xt_read, NULL, NULL, keyboard_xt_write, NULL, NULL, NULL); + keyboard_xt_reset(); + keyboard_send = keyboard_xt_adddata; + keyboard_poll = keyboard_xt_poll; + keyboard_xt.tandy = 0; + + timer_add(keyboard_xt_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} + +void keyboard_tandy_init() +{ + //return; + io_sethandler(0x0060, 0x0004, keyboard_xt_read, NULL, NULL, keyboard_xt_write, NULL, NULL, NULL); + keyboard_xt_reset(); + keyboard_send = keyboard_xt_adddata; + keyboard_poll = keyboard_xt_poll; + keyboard_xt.tandy = (romset != ROM_TANDY) ? 1 : 0; + + timer_add(keyboard_xt_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_xt.h b/src/keyboard_xt.h new file mode 100644 index 000000000..edbc82945 --- /dev/null +++ b/src/keyboard_xt.h @@ -0,0 +1,4 @@ +void keyboard_xt_init(); +void keyboard_tandy_init(); +void keyboard_xt_reset(); +void keyboard_xt_poll(); diff --git a/src/linux-time.c b/src/linux-time.c new file mode 100644 index 000000000..8b7511d84 --- /dev/null +++ b/src/linux-time.c @@ -0,0 +1,48 @@ +#include +#include +#include "ibm.h" +#include "nvr.h" + +void time_get(char *nvrram) +{ + int c,d; + uint8_t baknvr[10]; + time_t cur_time; + struct tm cur_time_tm; + + memcpy(baknvr,nvrram,10); + + cur_time = time(NULL); + localtime_r(&cur_time, &cur_time_tm); + + d = cur_time_tm.tm_sec % 10; + c = cur_time_tm.tm_sec / 10; + nvrram[0] = d | (c << 4); + d = cur_time_tm.tm_min % 10; + c = cur_time_tm.tm_min / 10; + nvrram[2] = d | (c << 4); + d = cur_time_tm.tm_hour % 10; + c = cur_time_tm.tm_hour / 10; + nvrram[4] = d | (c << 4); + d = cur_time_tm.tm_wday % 10; + c = cur_time_tm.tm_wday / 10; + nvrram[6] = d | (c << 4); + d = cur_time_tm.tm_mday % 10; + c = cur_time_tm.tm_mday / 10; + nvrram[7] = d | (c << 4); + d = cur_time_tm.tm_mon % 10; + c = cur_time_tm.tm_mon / 10; + nvrram[8] = d | (c << 4); + d = cur_time_tm.tm_year % 10; + c = (cur_time_tm.tm_year / 10) % 10; + nvrram[9] = d | (c << 4); + if (baknvr[0] != nvrram[0] || + baknvr[2] != nvrram[2] || + baknvr[4] != nvrram[4] || + baknvr[6] != nvrram[6] || + baknvr[7] != nvrram[7] || + baknvr[8] != nvrram[8] || + baknvr[9] != nvrram[9]) + nvrram[0xA] |= 0x80; +} + diff --git a/src/lpt.c b/src/lpt.c new file mode 100644 index 000000000..407dae254 --- /dev/null +++ b/src/lpt.c @@ -0,0 +1,95 @@ +#include "ibm.h" +#include "io.h" + +#include "lpt.h" + +static uint8_t lpt1_dat, lpt2_dat; +static uint8_t lpt1_ctrl, lpt2_ctrl; + +void lpt1_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port & 3) + { + case 0: + writedac(val); + lpt1_dat = val; + break; + case 2: + writedacctrl(val); + lpt1_ctrl = val; + break; + } +} +uint8_t lpt1_read(uint16_t port, void *priv) +{ + switch (port & 3) + { + case 0: + return lpt1_dat; + case 1: + return readdacfifo(); + case 2: + return lpt1_ctrl; + } + return 0xff; +} + +void lpt2_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port & 3) + { + case 0: + writedac(val); + lpt2_dat = val; + break; + case 2: + writedacctrl(val); + lpt2_ctrl = val; + break; + } +} +uint8_t lpt2_read(uint16_t port, void *priv) +{ + switch (port & 3) + { + case 0: + return lpt2_dat; + case 1: + return readdacfifo(); + case 2: + return lpt2_ctrl; + } + return 0xff; +} + +void lpt_init() +{ + io_sethandler(0x0378, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + io_sethandler(0x0278, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); +} + +void lpt1_init(uint16_t port) +{ + io_sethandler(port, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); +} +void lpt1_remove() +{ + io_removehandler(0x0278, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + io_removehandler(0x0378, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + io_removehandler(0x03bc, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); +} +void lpt2_init(uint16_t port) +{ + io_sethandler(port, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); +} +void lpt2_remove() +{ + io_removehandler(0x0278, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + io_removehandler(0x0378, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + io_removehandler(0x03bc, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); +} + +void lpt2_remove_ams() +{ + io_removehandler(0x0379, 0x0002, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); +} diff --git a/src/lpt.h b/src/lpt.h new file mode 100644 index 000000000..0df90a7e7 --- /dev/null +++ b/src/lpt.h @@ -0,0 +1,6 @@ +extern void lpt_init(); +extern void lpt1_init(uint16_t port); +extern void lpt1_remove(); +extern void lpt2_init(uint16_t port); +extern void lpt2_remove(); +extern void lpt2_remove_ams(); diff --git a/src/mcr.c b/src/mcr.c new file mode 100644 index 000000000..32f67fd63 --- /dev/null +++ b/src/mcr.c @@ -0,0 +1,37 @@ +/*INTEL 82355 MCR emulation + This chip was used as part of many 386 chipsets + It controls memory addressing and shadowing*/ +#include "ibm.h" + +int nextreg6; +uint8_t mcr22; +int mcrlock,mcrfirst; +void resetmcr() +{ + mcrlock=0; + mcrfirst=1; + shadowbios=0; +} + +void writemcr(uint16_t addr, uint8_t val) +{ + printf("Write MCR %04X %02X %04X:%04X\n",addr,val,CS,cpu_state.pc); + switch (addr) + { + case 0x22: + if (val==6 && mcr22==6) nextreg6=1; + else nextreg6=0; +// if ((val&1) && (mcr22&1)) shadowbios=1; +// if (!(val&1) && !(mcr22&1)) shadowbios=0; +// if (!mcrfirst) shadowbios=val&1; +// mcrfirst=0; +// dumpregs(); +// exit(-1); + break; + case 0x23: + if (nextreg6) shadowbios=!val; + break; + } + mcr22=val; +} + diff --git a/src/mem.c b/src/mem.c new file mode 100644 index 000000000..9a4fb8da7 --- /dev/null +++ b/src/mem.c @@ -0,0 +1,2090 @@ +/*MESS ROM notes : + + - pc2386 BIOS is corrupt (JMP at F000:FFF0 points to RAM) + - pc2386 video BIOS is underdumped (16k instead of 24k) + - c386sx16 BIOS fails checksum +*/ + +#include +#include +#include "ibm.h" + +#include "config.h" +#include "mem.h" +#include "video.h" +#include "x86.h" +#include "cpu.h" +#include "rom.h" +#include "x86_ops.h" +#include "codegen.h" + +page_t *pages; +page_t **page_lookup; + +static uint8_t (*_mem_read_b[0x40000])(uint32_t addr, void *priv); +static uint16_t (*_mem_read_w[0x40000])(uint32_t addr, void *priv); +static uint32_t (*_mem_read_l[0x40000])(uint32_t addr, void *priv); +static void (*_mem_write_b[0x40000])(uint32_t addr, uint8_t val, void *priv); +static void (*_mem_write_w[0x40000])(uint32_t addr, uint16_t val, void *priv); +static void (*_mem_write_l[0x40000])(uint32_t addr, uint32_t val, void *priv); +static uint8_t *_mem_exec[0x40000]; +static void *_mem_priv_r[0x40000]; +static void *_mem_priv_w[0x40000]; +static mem_mapping_t *_mem_mapping_r[0x40000]; +static mem_mapping_t *_mem_mapping_w[0x40000]; +static int _mem_state[0x40000]; + +static mem_mapping_t base_mapping; +mem_mapping_t ram_low_mapping; +static mem_mapping_t ram_high_mapping; +static mem_mapping_t ram_mid_mapping; +static mem_mapping_t ram_remapped_mapping; +mem_mapping_t bios_mapping[8]; +mem_mapping_t bios_high_mapping[8]; +static mem_mapping_t romext_mapping; + +int shadowbios,shadowbios_write; + +static unsigned char isram[0x10000]; + +static uint8_t ff_array[0x1000]; + +int mem_size; +int cache=4; +uint32_t biosmask; +int readlnum=0,writelnum=0; +int cachesize=256; + +uint8_t *ram,*rom,*vram; +uint8_t romext[32768]; + +static void mem_load_xtide_bios() +{ + FILE *f; + f=romfopen("roms/ide_xt.bin","rb"); + +// is486=0; + if (f) + { + fread(romext,16384,1,f); + mem_mapping_enable(&romext_mapping); + fclose(f); + } +} + +static void mem_load_atide_bios() +{ + FILE *f; + f=romfopen("roms/ide_at.bin","rb"); + +// is486=0; + if (f) + { + fread(romext,16384,1,f); + mem_mapping_enable(&romext_mapping); + fclose(f); + } +} + +static void mem_load_atide115_bios() +{ + FILE *f; + f=romfopen("roms/ide_at_1_1_5.bin","rb"); + +// is486=0; + if (f) + { + fread(romext,16384,1,f); + mem_mapping_enable(&romext_mapping); + fclose(f); + } +} + +int loadbios() +{ + FILE *f=NULL,*ff=NULL; + int c; + + loadfont("roms/mda.rom", 0); + + biosmask = 0xffff; + + memset(romext,0xff,0x8000); + memset(rom, 0xff, 0x20000); + + pclog("Starting with romset %i\n", romset); + + mem_mapping_disable(&romext_mapping); + + switch (romset) + { + case ROM_PC1512: + f=romfopen("roms/pc1512/40043.v1","rb"); + ff=romfopen("roms/pc1512/40044.v1","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + loadfont("roms/pc1512/40078.ic127", 2); + return 1; + case ROM_PC1640: + f=romfopen("roms/pc1640/40044.v3","rb"); + ff=romfopen("roms/pc1640/40043.v3","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + f=romfopen("roms/pc1640/40100","rb"); + if (!f) break; + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_PC200: + f=romfopen("roms/pc200/pc20v2.1","rb"); + ff=romfopen("roms/pc200/pc20v2.0","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + loadfont("roms/pc200/40109.bin", 1); + return 1; + case ROM_TANDY: + f=romfopen("roms/tandy/tandy1t1.020","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_TANDY1000HX: + f = romfopen("roms/tandy1000hx/v020000.u12", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + mem_load_xtide_bios(); + return 1; + case ROM_TANDY1000SL2: + f = romfopen("roms/tandy1000sl2/8079047.hu1" ,"rb"); + ff = romfopen("roms/tandy1000sl2/8079048.hu2","rb"); + if (!f || !ff) break; + fseek(f, 0x30000/2, SEEK_SET); + fseek(ff, 0x30000/2, SEEK_SET); + for (c = 0x0000; c < 0x10000; c += 2) + { + rom[c] = getc(f); + rom[c + 1] = getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + return 1; +/* case ROM_IBMPCJR: + f=fopen("pcjr/bios.rom","rb"); + fread(rom+0xE000,8192,1,f); + fclose(f); + f=fopen("pcjr/basic.rom","rb"); + fread(rom+0x6000,32768,1,f); + fclose(f); + break;*/ + case ROM_IBMXT: + f=romfopen("roms/ibmxt/xt.rom","rb"); + if (!f) + { + f = romfopen("roms/ibmxt/5000027.u19", "rb"); + ff = romfopen("roms/ibmxt/1501512.u18","rb"); + if (!f || !ff) break; + fread(rom, 0x8000, 1, f); + fread(rom + 0x8000, 0x8000, 1, ff); + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + return 1; + } + else + { + fread(rom,65536,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + } + break; + + case ROM_IBMPCJR: + f = romfopen("roms/ibmpcjr/bios.rom","rb"); + if (!f) break; + fread(rom, 0x10000, 1, f); + fclose(f); + return 1; + + case ROM_GENXT: + f=romfopen("roms/genxt/pcxt.rom","rb"); + if (!f) break; + fread(rom+0xE000,8192,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_DTKXT: + f=romfopen("roms/dtk/DTK_ERSO_2.42_2764.bin","rb"); + if (!f) break; + fread(rom+0xE000,8192,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_OLIM24: + f = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_low.bin" ,"rb"); + ff = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_high.bin","rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x4000; c += 2) + { + rom[c + 0xc000] = getc(f); + rom[c + 0xc001] = getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_PC2086: + f = romfopen("roms/pc2086/40179.ic129" ,"rb"); + ff = romfopen("roms/pc2086/40180.ic132","rb"); + if (!f || !ff) break; + pclog("Loading BIOS\n"); + for (c = 0x0000; c < 0x4000; c += 2) + { + rom[c + 0x0000] = getc(f); + rom[c + 0x0001] = getc(ff); + } + pclog("%02X %02X %02X\n", rom[0xfff0], rom[0xfff1], rom[0xfff2]); + fclose(ff); + fclose(f); + f = romfopen("roms/pc2086/40186.ic171", "rb"); + if (!f) break; + fclose(f); + mem_load_xtide_bios(); + biosmask = 0x3fff; + return 1; + + case ROM_PC3086: + f = romfopen("roms/pc3086/fc00.bin" ,"rb"); + if (!f) break; + fread(rom, 0x4000, 1, f); + fclose(f); + f = romfopen("roms/pc3086/c000.bin", "rb"); + if (!f) break; + fclose(f); + mem_load_xtide_bios(); + biosmask = 0x3fff; + return 1; + + case ROM_IBMAT: +/* f=romfopen("roms/AMIC206.BIN","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1;*/ + case ROM_IBMAT386: + f = romfopen("roms/ibmat/62x0820.u27", "rb"); + ff =romfopen("roms/ibmat/62x0821.u47", "rb"); + if (!f || !ff) break; + for (c=0x0000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + mem_load_atide_bios(); + return 1; + case ROM_CMDPC30: + f = romfopen("roms/cmdpc30/commodore pc 30 iii even.bin", "rb"); + ff = romfopen("roms/cmdpc30/commodore pc 30 iii odd.bin", "rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x8000; c += 2) + { + rom[c] = getc(f); + rom[c + 1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x7fff; + mem_load_atide_bios(); + return 1; + case ROM_DELL200: + f=romfopen("roms/dells200/dell0.bin","rb"); + ff=romfopen("roms/dells200/dell1.bin","rb"); + if (!f || !ff) break; + for (c=0x0000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + return 1; +/* case ROM_IBMAT386: + f=romfopen("roms/at386/at386.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1;*/ + case ROM_AMI386: /*This uses the OPTi 82C495 chipset*/ +// f=romfopen("roms/at386/at386.bin","rb"); + f=romfopen("roms/ami386/ami386.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1; + + + case ROM_ACER386: + f=romfopen("roms/acer386/acer386.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + rom[0xB0]=0xB0-0x51; + rom[0x40d4]=0x51; /*PUSH CX*/ + f=romfopen("roms/acer386/oti067.bin","rb"); + if (!f) break; + fclose(f); + return 1; + + case ROM_AMI286: + f=romfopen("roms/ami286/amic206.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); +// memset(romext,0x63,0x8000); + return 1; + + case ROM_AWARD286: + f=romfopen("roms/award286/award.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_EUROPC: +// return 0; + f=romfopen("roms/europc/50145","rb"); + if (!f) break; + fread(rom+0x8000,32768,1,f); + fclose(f); +// memset(romext,0x63,0x8000); + return 1; + + case ROM_IBMPC: + f=romfopen("roms/ibmpc/pc102782.bin","rb"); + if (!f) break; +// f=fopen("pc081682.bin","rb"); + fread(rom+0xE000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.f6","rb"); + if (!f) return 1; /*I don't really care if BASIC is there or not*/ + fread(rom+0x6000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.f8","rb"); + if (!f) break; /*But if some of it is there, then all of it must be*/ + fread(rom+0x8000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.fa","rb"); + if (!f) break; + fread(rom+0xA000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.fc","rb"); + if (!f) break; + fread(rom+0xC000,8192,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_MEGAPC: + f = romfopen("roms/megapc/41651-bios lo.u18", "rb"); + ff = romfopen("roms/megapc/211253-bios hi.u19", "rb"); + if (!f || !ff) break; + fseek(f, 0x8000, SEEK_SET); + fseek(ff, 0x8000, SEEK_SET); + for (c = 0x0000; c < 0x10000; c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + return 1; + + case ROM_AMI486: + f=romfopen("roms/ami486/ami486.BIN","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + //is486=1; + return 1; + + case ROM_WIN486: +// f=romfopen("roms/win486/win486.bin","rb"); + f=romfopen("roms/win486/ALI1429G.AMW","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + //is486=1; + return 1; + + case ROM_PCI486: + f=romfopen("roms/hot-433/hot-433.ami","rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_SIS496: + f = romfopen("roms/sis496/SIS496-1.AWA", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + pclog("Load SIS496 %x %x\n", rom[0x1fff0], rom[0xfff0]); + return 1; + + case ROM_430VX: +// f = romfopen("roms/430vx/Ga586atv.bin", "rb"); +// f = fopen("roms/430vx/vx29.BIN", "rb"); + f = romfopen("roms/430vx/55XWUQ0E.BIN", "rb"); +// f=romfopen("roms/430vx/430vx","rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_REVENGE: + f = romfopen("roms/revenge/1009AF2_.BIO", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("roms/revenge/1009AF2_.BI1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom, 0xc000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + case ROM_ENDEAVOR: + f = romfopen("roms/endeavor/1006CB0_.BIO", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("roms/endeavor/1006CB0_.BI1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom, 0xd000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_IBMPS1_2011: +#if 0 + f=romfopen("roms/ibmps1es/ibm_1057757_24-05-90.bin","rb"); + ff=romfopen("roms/ibmps1es/ibm_1057757_29-15-90.bin","rb"); + fseek(f, 0x10000, SEEK_SET); + fseek(ff, 0x10000, SEEK_SET); + if (!f || !ff) break; + for (c = 0x0000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); +#endif +//#if 0 + f = romfopen("roms/ibmps1es/f80000.bin", "rb"); + if (!f) break; + fseek(f, 0x60000, SEEK_SET); + fread(rom, 0x20000, 1, f); + fclose(f); +//#endif + biosmask = 0x1ffff; + mem_load_atide115_bios(); + return 1; + + case ROM_IBMPS1_2121: + f = romfopen("roms/ibmps1_2121/fc0000.bin", "rb"); + if (!f) break; + fseek(f, 0x20000, SEEK_SET); + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_DESKPRO_386: + f=romfopen("roms/deskpro386/109592-005.U11.bin","rb"); + ff=romfopen("roms/deskpro386/109591-005.U13.bin","rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x8000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x7fff; + mem_load_atide_bios(); + return 1; + + case ROM_AMIXT: + f = romfopen("roms/amixt/AMI_8088_BIOS_31JAN89.BIN", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_LTXT: + f = romfopen("roms/ltxt/27C64.bin", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_LXT3: + f = romfopen("roms/lxt3/27C64D.bin", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_PX386: /*Phoenix 80386 BIOS*/ + f=romfopen("roms/px386/3iip001l.bin","rb"); + ff=romfopen("roms/px386/3iip001h.bin","rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x10000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); + mem_load_atide_bios(); + return 1; + + case ROM_DTK386: /*Uses NEAT chipset*/ + f = romfopen("roms/dtk386/3cto001.bin", "rb"); + if (!f) break; + fread(rom, 65536, 1, f); + fclose(f); + mem_load_atide_bios(); + return 1; + + case ROM_PXXT: + f = romfopen("roms/pxxt/000p001.bin", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_JUKOPC: + f = romfopen("roms/jukopc/000o001.bin", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_DTK486: + f = romfopen("roms/dtk486/4siw005.bin", "rb"); + if (!f) break; + fread(rom, 0x10000, 1, f); + fclose(f); + return 1; + + case ROM_R418: + f = romfopen("roms/r418/r418i.bin", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + pclog("Load R418 %x %x\n", rom[0x1fff0], rom[0xfff0]); + return 1; + + case ROM_586MC1: + f = romfopen("roms/586mc1/IS.34", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_PLATO: + f = romfopen("roms/plato/1016AX1_.BIO", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("roms/plato/1016AX1_.BI1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom, 0xd000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_MB500N: + f = romfopen("roms/mb500n/031396S.BIN", "rb"); /* Works */ + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P54TP4XE: + f = romfopen("roms/p54tp4xe/T15I0302.AWD", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ACERM3A: + f = romfopen("roms/acerm3a/r01-b3.bin", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ACERV35N: + f = romfopen("roms/acerv35n/V35ND1S1.BIN", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55T2P4: + f = romfopen("roms/p55t2p4/0207_J2.BIN", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55TVP4: + f = romfopen("roms/p55tvp4/tv5i0201.awd", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55VA: + f = romfopen("roms/p55va/VA021297.BIN", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_440FX: + f = romfopen("roms/440fx/NTMAW501.BIN", "rb"); /* Working Tyan BIOS. */ + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_KN97: + f = romfopen("roms/kn97/NAKI0116.AWD", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + } + printf("Failed to load ROM!\n"); + if (f) fclose(f); + if (ff) fclose(ff); + return 0; +} + + + +int abrt=0; + +void resetreadlookup() +{ + int c; +// /*if (output) */pclog("resetreadlookup\n"); + memset(readlookup2,0xFF,1024*1024*sizeof(uintptr_t)); + for (c=0;c<256;c++) readlookup[c]=0xFFFFFFFF; + readlnext=0; + memset(writelookup2,0xFF,1024*1024*sizeof(uintptr_t)); + memset(page_lookup, 0, (1 << 20) * sizeof(page_t *)); + for (c=0;c<256;c++) writelookup[c]=0xFFFFFFFF; + writelnext=0; + pccache=0xFFFFFFFF; +// readlnum=writelnum=0; + +} + +int mmuflush=0; +int mmu_perm=4; + +void flushmmucache() +{ + int c; +// /*if (output) */pclog("flushmmucache\n"); +/* for (c=0;c<16;c++) + { + if ( readlookup2[0xE0+c]!=0xFFFFFFFF) pclog("RL2 %02X = %08X\n",0xE0+c, readlookup2[0xE0+c]); + if (writelookup2[0xE0+c]!=0xFFFFFFFF) pclog("WL2 %02X = %08X\n",0xE0+c,writelookup2[0xE0+c]); + }*/ + for (c=0;c<256;c++) + { + if (readlookup[c]!=0xFFFFFFFF) + { + readlookup2[readlookup[c]] = -1; + readlookup[c]=0xFFFFFFFF; + } + if (writelookup[c] != 0xFFFFFFFF) + { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xFFFFFFFF; + } + } + mmuflush++; +// readlnum=writelnum=0; + pccache=(uint32_t)0xFFFFFFFF; + pccache2=(uint8_t *)0xFFFFFFFF; + +// memset(readlookup,0xFF,sizeof(readlookup)); +// memset(readlookup2,0xFF,1024*1024*4); +// memset(writelookup,0xFF,sizeof(writelookup)); +// memset(writelookup2,0xFF,1024*1024*4); +/* if (!(cr0>>31)) return;*/ + +/* for (c = 0; c < 1024*1024; c++) + { + if (readlookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + if (writelookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + }*/ + codegen_flush(); +} + +void flushmmucache_nopc() +{ + int c; + for (c=0;c<256;c++) + { + if (readlookup[c]!=0xFFFFFFFF) + { + readlookup2[readlookup[c]] = -1; + readlookup[c]=0xFFFFFFFF; + } + if (writelookup[c] != 0xFFFFFFFF) + { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xFFFFFFFF; + } + } +} + +void flushmmucache_cr3() +{ + int c; +// /*if (output) */pclog("flushmmucache_cr3\n"); + for (c=0;c<256;c++) + { + if (readlookup[c]!=0xFFFFFFFF)// && !readlookupp[c]) + { + readlookup2[readlookup[c]] = -1; + readlookup[c]=0xFFFFFFFF; + } + if (writelookup[c] != 0xFFFFFFFF)// && !writelookupp[c]) + { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xFFFFFFFF; + } + } +/* for (c = 0; c < 1024*1024; c++) + { + if (readlookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + if (writelookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + }*/ +} + +void mem_flush_write_page(uint32_t addr, uint32_t virt) +{ + int c; + page_t *page_target = &pages[addr >> 12]; +// pclog("mem_flush_write_page %08x %08x\n", virt, addr); + + for (c = 0; c < 256; c++) + { + if (writelookup[c] != 0xffffffff) + { + uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; + +// if ((virt & ~0xfff) == 0xc022e000) +// pclog(" Checking %02x %p %p\n", (void *)writelookup2[writelookup[c]], (void *)target); + if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) + { +// pclog(" throw out %02x %p %p\n", writelookup[c], (void *)page_lookup[writelookup[c]], (void *)writelookup2[writelookup[c]]); + writelookup2[writelookup[c]] = -1; + page_lookup[writelookup[c]] = NULL; + writelookup[c] = 0xffffffff; + } + } + } +} + +extern int output; + +#define mmutranslate_read(addr) mmutranslatereal(addr,0) +#define mmutranslate_write(addr) mmutranslatereal(addr,1) + +int pctrans=0; + +extern uint32_t testr[9]; + +uint32_t mmutranslatereal(uint32_t addr, int rw) +{ + uint32_t addr2; + uint32_t temp,temp2,temp3; + + if (abrt) + { +// pclog("Translate recursive abort\n"); + return -1; + } +/* if ((addr&~0xFFFFF)==0x77f00000) pclog("Do translate %08X %i %08X %08X\n",addr,rw,EAX,cpu_state.pc); + if (addr==0x77f61000) output = 3; + if (addr==0x77f62000) { dumpregs(); exit(-1); } + if (addr==0x77f9a000) { dumpregs(); exit(-1); }*/ + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp=temp2=((uint32_t *)ram)[addr2>>2]; +// if (output == 3) pclog("Do translate %08X %i %08X\n", addr, rw, temp); + if (!(temp&1))// || (CPL==3 && !(temp&4) && !cpl_override) || (rw && !(temp&2) && (CPL==3 || cr0&WP_FLAG))) + { +// if (!nopageerrors) pclog("Section not present! %08X %08X %02X %04X:%08X %i %i\n",addr,temp,opcode,CS,cpu_state.pc,CPL,rw); + + cr2=addr; + temp&=1; + if (CPL==3) temp|=4; + if (rw) temp|=2; + abrt = ABRT_PF; + abrt_error = temp; +/* if (addr == 0x70046D) + { + dumpregs(); + exit(-1); + }*/ + return -1; + } + temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2]; + temp3=temp&temp2; +// if (output == 3) pclog("Do translate %08X %08X\n", temp, temp3); + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) + { +// if (!nopageerrors) pclog("Page not present! %08X %08X %02X %02X %i %08X %04X:%08X %04X:%08X %i %i %i\n",addr,temp,opcode,opcode2,frame,rmdat32, CS,cpu_state.pc,SS,ESP,ins,CPL,rw); + +// dumpregs(); +// exit(-1); +// if (addr == 0x815F6E90) output = 3; +/* if (addr == 0x10ADE020) output = 3;*/ +/* if (addr == 0x10150010 && !nopageerrors) + { + dumpregs(); + exit(-1); + }*/ + + cr2=addr; + temp&=1; + if (CPL==3) temp|=4; + if (rw) temp|=2; + abrt = ABRT_PF; + abrt_error = temp; +// pclog("%04X\n",abrt); + return -1; + } + mmu_perm=temp&4; + ((uint32_t *)ram)[addr2>>2]|=0x20; + ((uint32_t *)ram)[((temp2&~0xFFF)+((addr>>10)&0xFFC))>>2]|=(rw?0x60:0x20); +// /*if (output) */pclog("Translate %08X %08X %08X %08X:%08X %08X\n",addr,(temp&~0xFFF)+(addr&0xFFF),temp,cs,cpu_state.pc,EDI); + + return (temp&~0xFFF)+(addr&0xFFF); +} + +uint32_t mmutranslate_noabrt(uint32_t addr, int rw) +{ + uint32_t addr2; + uint32_t temp,temp2,temp3; + + if (abrt) + return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp=temp2=((uint32_t *)ram)[addr2>>2]; + + if (!(temp&1)) + return -1; + + temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2]; + temp3=temp&temp2; + + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) + return -1; + + return (temp&~0xFFF)+(addr&0xFFF); +} + +void mmu_invalidate(uint32_t addr) +{ +// readlookup2[addr >> 12] = writelookup2[addr >> 12] = 0xFFFFFFFF; + flushmmucache_cr3(); +} + +int memspeed[11]={256,320,384,512,640,768,1024,1152,1280,1536,1920}; +int memwaitstate; + +static int cachelookup[256]; +static uint8_t *cachelookup2; +static int cachelnext; + +void addreadlookup(uint32_t virt, uint32_t phys) +{ +// return; +// printf("Addreadlookup %08X %08X %08X %08X %08X %08X %02X %08X\n",virt,phys,cs,ds,es,ss,opcode,cpu_state.pc); + if (virt == 0xffffffff) + return; + + if (readlookup2[virt>>12] != -1) + { +/* if (readlookup2[virt>>12] != phys&~0xfff) + { + pclog("addreadlookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12); + dumpregs(); + exit(-1); + }*/ + return; + } + + + if (!cachelookup2[phys >> 12]) + { + readlnum++; + cycles-=memwaitstate; + if (cachelookup[cachelnext] != 0xffffffff) + cachelookup2[cachelookup[cachelnext]] = 0; + cachelookup[cachelnext] = phys >> 12; + cachelookup2[phys >> 12] = 1; + cachelnext = (cachelnext + 1) & (cachesize - 1); + } + + if (readlookup[readlnext]!=0xFFFFFFFF) + { + readlookup2[readlookup[readlnext]] = -1; +// readlnum--; + } + readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + readlookupp[readlnext]=mmu_perm; + readlookup[readlnext++]=virt>>12; + readlnext&=(cachesize-1); + + cycles -= 9; +} + +void addwritelookup(uint32_t virt, uint32_t phys) +{ +// return; +// printf("Addwritelookup %08X %08X\n",virt,phys); + if (virt == 0xffffffff) + return; + + if (page_lookup[virt >> 12]) + { +/* if (writelookup2[virt>>12] != phys&~0xfff) + { + pclog("addwritelookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12); + dumpregs(); + exit(-1); + }*/ + return; + } + + if (!cachelookup2[phys >> 12]) + { + writelnum++; + cycles-=memwaitstate; + if (cachelookup[cachelnext] != 0xffffffff) + cachelookup2[cachelookup[cachelnext]] = 0; + cachelookup[cachelnext] = phys >> 12; + cachelookup2[phys >> 12] = 1; + cachelnext = (cachelnext + 1) & (cachesize - 1); + } + + cycles-=memwaitstate; + if (writelookup[writelnext] != -1) + { + page_lookup[writelookup[writelnext]] = NULL; + writelookup2[writelookup[writelnext]] = -1; +// writelnum--; + } +// if (page_lookup[virt >> 12] && (writelookup2[virt>>12] != 0xffffffff)) +// fatal("Bad write mapping\n"); + + if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page) + page_lookup[virt >> 12] = &pages[phys >> 12];//(uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + else + writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; +// pclog("addwritelookup %08x %08x %p %p %016llx %p\n", virt, phys, (void *)page_lookup[virt >> 12], (void *)writelookup2[virt >> 12], pages[phys >> 12].dirty_mask, (void *)&pages[phys >> 12]); + writelookupp[writelnext] = mmu_perm; + writelookup[writelnext++] = virt >> 12; + writelnext &= (cachesize - 1); + + cycles -= 9; +} + +#undef printf +uint8_t *getpccache(uint32_t a) +{ + uint32_t a2=a; + + if (cr0>>31) + { + pctrans=1; + a = mmutranslate_read(a); + pctrans=0; + + if (a==0xFFFFFFFF) return ram; + } + a&=rammask; + + if (isram[a>>16]) + { + if ((a >> 16) != 0xF || shadowbios) + addreadlookup(a2, a); + return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)]; + } + + if (_mem_exec[a >> 14]) + { + return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xFFF)]; + } + + pclog("Bad getpccache %08X\n", a); + return &ff_array[0-(uintptr_t)(a2 & ~0xFFF)]; +} +#define printf pclog + +uint32_t mem_logical_addr; +uint8_t readmembl(uint32_t addr) +{ + mem_logical_addr = addr; + if (cr0 >> 31) + { + addr = mmutranslate_read(addr); + if (addr == 0xFFFFFFFF) return 0xFF; + } + addr &= rammask; + + if (_mem_read_b[addr >> 14]) return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); +// pclog("Bad readmembl %08X %04X:%08X\n", addr, CS, pc); + return 0xFF; +} + +void writemembl(uint32_t addr, uint8_t val) +{ + mem_logical_addr = addr; + + if (page_lookup[addr>>12]) + { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0 >> 31) + { + addr = mmutranslate_write(addr); + if (addr == 0xFFFFFFFF) return; + } + addr &= rammask; + + if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +// else pclog("Bad writemembl %08X %02X %04X:%08X\n", addr, val, CS, pc); +} + +uint8_t readmemb386l(uint32_t seg, uint32_t addr) +{ + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rb %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return -1; + } + mem_logical_addr = addr = addr + seg; +/* if (readlookup2[mem_logical_addr >> 12] != 0xFFFFFFFF) + { + return ram[readlookup2[mem_logical_addr >> 12] + (mem_logical_addr & 0xFFF)]; + }*/ + + if (cr0 >> 31) + { + addr = mmutranslate_read(addr); + if (addr == 0xFFFFFFFF) return 0xFF; + } + + addr &= rammask; + + if (_mem_read_b[addr >> 14]) return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); +// pclog("Bad readmemb386l %08X %04X:%08X\n", addr, CS, pc); + return 0xFF; +} + +void writememb386l(uint32_t seg, uint32_t addr, uint8_t val) +{ + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! wb %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return; + } + + mem_logical_addr = addr = addr + seg; + if (page_lookup[addr>>12]) + { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0 >> 31) + { + addr = mmutranslate_write(addr); + if (addr == 0xFFFFFFFF) return; + } + + addr &= rammask; + +/* if (addr >= 0xa0000 && addr < 0xc0000) + pclog("writemembl %08X %02X\n", addr, val);*/ + + if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +// else pclog("Bad writememb386l %08X %02X %04X:%08X\n", addr, val, CS, pc); +} + +uint16_t readmemwl(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFFE) + { + if (cr0>>31) + { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; + if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff; + } + if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8); + else return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8); + } + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rw %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return -1; + } + if (cr0>>31) + { + addr2 = mmutranslate_read(addr2); + if (addr2==0xFFFFFFFF) return 0xFFFF; + } + + addr2 &= rammask; + + if (_mem_read_w[addr2 >> 14]) return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + + if (_mem_read_b[addr2 >> 14]) + { + if (AT) return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8); + else return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14]) << 8); + } +// pclog("Bad readmemwl %08X\n", addr2); + return 0xffff; +} + +void writememwl(uint32_t seg, uint32_t addr, uint16_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFFE) + { + if (cr0>>31) + { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+1) == 0xffffffff) return; + } + if (is386) + { + writememb386l(seg,addr,val); + writememb386l(seg,addr+1,val>>8); + } + else + { + writemembl(seg+addr,val); + writemembl(seg+addr+1,val>>8); + } + return; + } + + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! ww %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return; + } + if (page_lookup[addr2>>12]) + { + page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]); + return; + } + if (cr0>>31) + { + addr2 = mmutranslate_write(addr2); + if (addr2==0xFFFFFFFF) return; + } + + addr2 &= rammask; + +/* if (addr2 >= 0xa0000 && addr2 < 0xc0000) + pclog("writememwl %08X %02X\n", addr2, val);*/ + + if (_mem_write_w[addr2 >> 14]) + { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + return; + } + + if (_mem_write_b[addr2 >> 14]) + { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[(addr2 + 1) >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + return; + } +// pclog("Bad writememwl %08X %04X\n", addr2, val); +} + +uint32_t readmemll(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFFC) + { + if (cr0>>31) + { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff; + } + return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); + } + + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return -1; + } + + if (cr0>>31) + { + addr2 = mmutranslate_read(addr2); + if (addr2==0xFFFFFFFF) return 0xFFFFFFFF; + } + + addr2&=rammask; + + if (_mem_read_l[addr2 >> 14]) return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + + if (_mem_read_w[addr2 >> 14]) return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16); + + if (_mem_read_b[addr2 >> 14]) return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8) | (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16) | (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14]) << 24); + +// pclog("Bad readmemll %08X\n", addr2); + return 0xffffffff; +} + +void writememll(uint32_t seg, uint32_t addr, uint32_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if ((addr2&0xFFF)>0xFFC) + { + if (cr0>>31) + { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+3) == 0xffffffff) return; + } + writememwl(seg,addr,val); + writememwl(seg,addr+2,val>>16); + return; + } + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return; + } + if (page_lookup[addr2>>12]) + { + page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); + return; + } + if (cr0>>31) + { + addr2 = mmutranslate_write(addr2); + if (addr2==0xFFFFFFFF) return; + } + + addr2&=rammask; + +/* if (addr >= 0xa0000 && addr < 0xc0000) + pclog("writememll %08X %08X\n", addr, val);*/ + + if (_mem_write_l[addr2 >> 14]) + { + _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_w[addr2 >> 14]) + { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_b[addr2 >> 14]) + { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); + return; + } +// pclog("Bad writememll %08X %08X\n", addr2, val); +} + +uint64_t readmemql(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFF8) + { + if (cr0>>31) + { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff; + } + return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); + } + + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return -1; + } + + if (cr0>>31) + { + addr2 = mmutranslate_read(addr2); + if (addr2==0xFFFFFFFF) return 0xFFFFFFFF; + } + + addr2&=rammask; + + if (_mem_read_l[addr2 >> 14]) + return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint64_t)_mem_read_l[addr2 >> 14](addr2 + 4, _mem_priv_r[addr2 >> 14]) << 32); + + return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); +} + +void writememql(uint32_t seg, uint32_t addr, uint64_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if ((addr2 & 0xFFF) > 0xFF8) + { + if (cr0>>31) + { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+7) == 0xffffffff) return; + } + writememll(seg, addr, val); + writememll(seg, addr+4, val >> 32); + return; + } + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return; + } + if (page_lookup[addr2>>12]) + { + page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); + page_lookup[addr2>>12]->write_l(addr2 + 4, val >> 32, page_lookup[addr2>>12]); + return; + } + if (cr0>>31) + { + addr2 = mmutranslate_write(addr2); + if (addr2==0xFFFFFFFF) return; + } + + addr2&=rammask; + + if (_mem_write_l[addr2 >> 14]) + { + _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_l[addr2 >> 14](addr2+4, val >> 32, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_w[addr2 >> 14]) + { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_b[addr2 >> 14]) + { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 5, val >> 40, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 7, val >> 56, _mem_priv_w[addr2 >> 14]); + return; + } +// pclog("Bad writememql %08X %08X\n", addr2, val); +} + +uint8_t mem_readb_phys(uint32_t addr) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + +void mem_writeb_phys(uint32_t addr, uint8_t val) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + +uint8_t mem_read_ram(uint32_t addr, void *priv) +{ +// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMb %08X\n", addr); + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} +uint16_t mem_read_ramw(uint32_t addr, void *priv) +{ +// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMw %08X\n", addr); + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} +uint32_t mem_read_raml(uint32_t addr, void *priv) +{ +// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMl %08X\n", addr); + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} + +void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) +{ + if (val != p->mem[addr & 0xfff] || codegen_in_recompile) + { + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); +// pclog("mem_write_ramb_page: %08x %02x %08x %llx %llx\n", addr, val, cs+pc, p->dirty_mask, mask); + p->dirty_mask |= mask; + p->mem[addr & 0xfff] = val; + } +} +void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) +{ + if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) + { + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0x3f) == 0x3f) + mask |= (mask << 1); +// pclog("mem_write_ramw_page: %08x %04x %08x\n", addr, val, cs+pc); + p->dirty_mask |= mask; + *(uint16_t *)&p->mem[addr & 0xfff] = val; + } +} +void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) +{ + if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) + { + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0x3f) >= 0x3d) + mask |= (mask << 1); +// pclog("mem_write_raml_page: %08x %08x %08x\n", addr, val, cs+pc); + p->dirty_mask |= mask; + *(uint32_t *)&p->mem[addr & 0xfff] = val; + } +} + +void mem_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); +} +void mem_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); +} +void mem_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); +} + +uint8_t mem_read_bios(uint32_t addr, void *priv) +{ + if (AMIBIOS && (addr&0xFFFFF)==0xF8281) /*This is read constantly during AMIBIOS POST, but is never written to. It's clearly a status register of some kind, but for what?*/ + { +// pclog("Read magic addr %04X(%06X):%04X\n",CS,cs,cpu_state.pc); +// if (pc==0x547D) output=3; + return 0x40; + } +// pclog("Read BIOS %08X %02X %04X:%04X\n", addr, rom[addr & biosmask], CS, pc); + return rom[addr & biosmask]; +} +uint16_t mem_read_biosw(uint32_t addr, void *priv) +{ +// pclog("Read BIOS %08X %04X %04X:%04X\n", addr, *(uint16_t *)&rom[addr & biosmask], CS, pc); + return *(uint16_t *)&rom[addr & biosmask]; +} +uint32_t mem_read_biosl(uint32_t addr, void *priv) +{ +// pclog("Read BIOS %08X %02X %04X:%04X\n", addr, *(uint32_t *)&rom[addr & biosmask], CS, pc); + return *(uint32_t *)&rom[addr & biosmask]; +} + +uint8_t mem_read_romext(uint32_t addr, void *priv) +{ + return romext[addr & 0x7fff]; +} +uint16_t mem_read_romextw(uint32_t addr, void *priv) +{ + return *(uint16_t *)&romext[addr & 0x7fff]; +} +uint32_t mem_read_romextl(uint32_t addr, void *priv) +{ + return *(uint32_t *)&romext[addr & 0x7fff]; +} + +void mem_write_null(uint32_t addr, uint8_t val, void *p) +{ +} +void mem_write_nullw(uint32_t addr, uint16_t val, void *p) +{ +} +void mem_write_nulll(uint32_t addr, uint32_t val, void *p) +{ +} + +void mem_updatecache() +{ + flushmmucache(); + if (!is386) + { + cachesize=256; + memwaitstate=0; + return; + } + if (cpu_16bitbus) + memwaitstate = 512 * ((cpu_multi >= 2) ? 2 : cpu_multi); + else + memwaitstate = 384 * ((cpu_multi >= 2) ? 2 : cpu_multi); //memspeed[cpuspeed]; + switch (cache) + { + case 0: cachesize=32; break; + case 1: cachesize=64; break; + case 2: cachesize=128; break; + case 3: cachesize=256; break; + case 4: cachesize=256; memwaitstate=0; break; + } +} + +void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) +{ + start_addr &= ~PAGE_MASK_MASK; + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + + for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) + { + uint64_t mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + pages[start_addr >> 12].dirty_mask |= mask; + } +} + +static inline int mem_mapping_read_allowed(uint32_t flags, int state) +{ +// pclog("mem_mapping_read_allowed: flags=%x state=%x\n", flags, state); + switch (state & MEM_READ_MASK) + { + case MEM_READ_ANY: + return 1; + case MEM_READ_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + case MEM_READ_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + default: + fatal("mem_mapping_read_allowed : bad state %x\n", state); + } +} + +static inline int mem_mapping_write_allowed(uint32_t flags, int state) +{ + switch (state & MEM_WRITE_MASK) + { + case MEM_WRITE_DISABLED: + return 0; + case MEM_WRITE_ANY: + return 1; + case MEM_WRITE_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + case MEM_WRITE_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + default: + fatal("mem_mapping_write_allowed : bad state %x\n", state); + } +} + +static void mem_mapping_recalc(uint64_t base, uint64_t size) +{ + uint64_t c; + mem_mapping_t *mapping = base_mapping.next; + + if (!size) + return; + /*Clear out old mappings*/ + for (c = base; c < base + size; c += 0x4000) + { + _mem_read_b[c >> 14] = NULL; + _mem_read_w[c >> 14] = NULL; + _mem_read_l[c >> 14] = NULL; + _mem_priv_r[c >> 14] = NULL; + _mem_mapping_r[c >> 14] = NULL; + _mem_write_b[c >> 14] = NULL; + _mem_write_w[c >> 14] = NULL; + _mem_write_l[c >> 14] = NULL; + _mem_priv_w[c >> 14] = NULL; + _mem_mapping_w[c >> 14] = NULL; + } + + /*Walk mapping list*/ + while (mapping != NULL) + { + /*In range?*/ + if (mapping->enable && (uint64_t)mapping->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)mapping->base + (uint64_t)mapping->size) > (uint64_t)base) + { + uint64_t start = (mapping->base < base) ? mapping->base : base; + uint64_t end = (((uint64_t)mapping->base + (uint64_t)mapping->size) < (base + size)) ? ((uint64_t)mapping->base + (uint64_t)mapping->size) : (base + size); + if (start < mapping->base) + start = mapping->base; + + for (c = start; c < end; c += 0x4000) + { + if ((mapping->read_b || mapping->read_w || mapping->read_l) && + mem_mapping_read_allowed(mapping->flags, _mem_state[c >> 14])) + { + _mem_read_b[c >> 14] = mapping->read_b; + _mem_read_w[c >> 14] = mapping->read_w; + _mem_read_l[c >> 14] = mapping->read_l; + if (mapping->exec) + _mem_exec[c >> 14] = mapping->exec + (c - mapping->base); + else + _mem_exec[c >> 14] = NULL; + _mem_priv_r[c >> 14] = mapping->p; + _mem_mapping_r[c >> 14] = mapping; + } + if ((mapping->write_b || mapping->write_w || mapping->write_l) && + mem_mapping_write_allowed(mapping->flags, _mem_state[c >> 14])) + { + _mem_write_b[c >> 14] = mapping->write_b; + _mem_write_w[c >> 14] = mapping->write_w; + _mem_write_l[c >> 14] = mapping->write_l; + _mem_priv_w[c >> 14] = mapping->p; + _mem_mapping_w[c >> 14] = mapping; + } + } + } + mapping = mapping->next; + } + flushmmucache_cr3(); +} + +void mem_mapping_add(mem_mapping_t *mapping, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t flags, + void *p) +{ + mem_mapping_t *dest = &base_mapping; + + /*Add mapping to the end of the list*/ + while (dest->next) + dest = dest->next; + dest->next = mapping; + + if (size) + mapping->enable = 1; + else + mapping->enable = 0; + mapping->base = base; + mapping->size = size; + mapping->read_b = read_b; + mapping->read_w = read_w; + mapping->read_l = read_l; + mapping->write_b = write_b; + mapping->write_w = write_w; + mapping->write_l = write_l; + mapping->exec = exec; + mapping->flags = flags; + mapping->p = p; + mapping->next = NULL; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_set_handler(mem_mapping_t *mapping, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)) +{ + mapping->read_b = read_b; + mapping->read_w = read_w; + mapping->read_l = read_l; + mapping->write_b = write_b; + mapping->write_w = write_w; + mapping->write_l = write_l; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_set_addr(mem_mapping_t *mapping, uint32_t base, uint32_t size) +{ + /*Remove old mapping*/ + mapping->enable = 0; + mem_mapping_recalc(mapping->base, mapping->size); + + /*Set new mapping*/ + mapping->enable = 1; + mapping->base = base; + mapping->size = size; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec) +{ + mapping->exec = exec; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_set_p(mem_mapping_t *mapping, void *p) +{ + mapping->p = p; +} + +void mem_mapping_disable(mem_mapping_t *mapping) +{ + mapping->enable = 0; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_enable(mem_mapping_t *mapping) +{ + mapping->enable = 1; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_set_mem_state(uint32_t base, uint32_t size, int state) +{ + uint32_t c; + +// pclog("mem_set_pci_enable: base=%08x size=%08x\n", base, size); + for (c = 0; c < size; c += 0x4000) + _mem_state[(c + base) >> 14] = state; + + mem_mapping_recalc(base, size); +} + +void mem_add_bios() +{ + if (AT) + { + mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + } + mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + + mem_mapping_add(&bios_high_mapping[0], 0xfffe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, 0, 0); + mem_mapping_add(&bios_high_mapping[1], 0xfffe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[2], 0xfffe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[3], 0xfffec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[4], 0xffff0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[5], 0xffff4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[6], 0xffff8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[7], 0xffffc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), 0, 0); +} + +int mem_a20_key = 0, mem_a20_alt = 0; +static int mem_a20_state = 1; + +void mem_init() +{ + int c; + + ram = malloc((mem_size + 384) * 1024); + rom = malloc(0x20000); + vram = malloc(0x800000); + readlookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); + writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); + cachelookup2 = malloc(1024 * 1024); + biosmask = 0xffff; + pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + page_lookup = malloc((1 << 20) * sizeof(page_t *)); + + memset(ram, 0, (mem_size + 384) * 1024); + memset(pages, 0, (((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + + memset(page_lookup, 0, (1 << 20) * sizeof(page_t *)); + + for (c = 0; c < (((mem_size + 384) * 1024) >> 12); c++) + { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } + + memset(isram, 0, sizeof(isram)); + for (c = 0; c < (mem_size / 256); c++) + { + isram[c] = 1; + if (c >= 0xa && c <= 0xf) + isram[c] = 0; + } + + memset(_mem_read_b, 0, sizeof(_mem_read_b)); + memset(_mem_read_w, 0, sizeof(_mem_read_w)); + memset(_mem_read_l, 0, sizeof(_mem_read_l)); + memset(_mem_write_b, 0, sizeof(_mem_write_b)); + memset(_mem_write_w, 0, sizeof(_mem_write_w)); + memset(_mem_write_l, 0, sizeof(_mem_write_l)); + memset(_mem_exec, 0, sizeof(_mem_exec)); + + memset(ff_array, 0xff, sizeof(ff_array)); + + memset(&base_mapping, 0, sizeof(base_mapping)); + + memset(_mem_state, 0, sizeof(_mem_state)); + + mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + mem_mapping_add(&ram_low_mapping, 0x00000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram, MEM_MAPPING_INTERNAL, NULL); + if (mem_size > 1024) + mem_mapping_add(&ram_high_mapping, 0x100000, ((mem_size - 1024) * 1024), mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + if (mem_size > 768) + mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); + + mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL, romext, 0, NULL); +// pclog("Mem resize %i %i\n",mem_size,c); +} + +void mem_remap_top_384k() +{ + int c; + + for (c = ((mem_size * 1024) >> 12); c < (((mem_size + 384) * 1024) >> 12); c++) + { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } + + for (c = (mem_size / 256); c < ((mem_size + 384) / 256); c++) + { + isram[c] = 1; + if (c >= 0xa && c <= 0xf) + isram[c] = 0; + } + + mem_set_mem_state(mem_size * 1024, 384 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 384 * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + (mem_size * 1024), MEM_MAPPING_INTERNAL, NULL); +} + +void mem_resize() +{ + int c; + + free(ram); + ram = malloc((mem_size + 384) * 1024); + memset(ram, 0, (mem_size + 384) * 1024); + + free(pages); + pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + memset(pages, 0, (((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + for (c = 0; c < (((mem_size + 384) * 1024) >> 12); c++) + { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } + + memset(isram, 0, sizeof(isram)); + for (c = 0; c < (mem_size / 256); c++) + { + isram[c] = 1; + if (c >= 0xa && c <= 0xf) + isram[c] = 0; + } + + memset(_mem_read_b, 0, sizeof(_mem_read_b)); + memset(_mem_read_w, 0, sizeof(_mem_read_w)); + memset(_mem_read_l, 0, sizeof(_mem_read_l)); + memset(_mem_write_b, 0, sizeof(_mem_write_b)); + memset(_mem_write_w, 0, sizeof(_mem_write_w)); + memset(_mem_write_l, 0, sizeof(_mem_write_l)); + memset(_mem_exec, 0, sizeof(_mem_exec)); + + memset(&base_mapping, 0, sizeof(base_mapping)); + + memset(_mem_state, 0, sizeof(_mem_state)); + + mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + mem_mapping_add(&ram_low_mapping, 0x00000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram, MEM_MAPPING_INTERNAL, NULL); + if (mem_size > 1024) + mem_mapping_add(&ram_high_mapping, 0x100000, (mem_size - 1024) * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + if (mem_size > 768) + mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); + + mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL, romext, 0, NULL); + +// pclog("Mem resize %i %i\n",mem_size,c); + mem_a20_key = 2; + mem_a20_recalc(); +} + +void mem_reset_page_blocks() +{ + int c; + + for (c = 0; c < ((mem_size * 1024) >> 12); c++) + { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + pages[c].block = NULL; + pages[c].block_2 = NULL; + } +} + +void mem_a20_recalc() +{ + int state = mem_a20_key | mem_a20_alt; +// pclog("A20 recalc %i %i\n", state, mem_a20_state); + if (state && !mem_a20_state) + { + rammask = 0xffffffff; + flushmmucache(); + } + else if (!state && mem_a20_state) + { + rammask = 0xffefffff; + flushmmucache(); + } +// pclog("rammask now %08X\n", rammask); + mem_a20_state = state; +} + +uint32_t get_phys_virt,get_phys_phys; diff --git a/src/mem.h b/src/mem.h new file mode 100644 index 000000000..1f927e44a --- /dev/null +++ b/src/mem.h @@ -0,0 +1,170 @@ +#ifndef _MEM_H_ +#define _MEM_H_ + +typedef struct mem_mapping_t +{ + struct mem_mapping_t *prev, *next; + + int enable; + + uint32_t base; + uint32_t size; + + uint8_t (*read_b)(uint32_t addr, void *priv); + uint16_t (*read_w)(uint32_t addr, void *priv); + uint32_t (*read_l)(uint32_t addr, void *priv); + void (*write_b)(uint32_t addr, uint8_t val, void *priv); + void (*write_w)(uint32_t addr, uint16_t val, void *priv); + void (*write_l)(uint32_t addr, uint32_t val, void *priv); + + uint8_t *exec; + + uint32_t flags; + + void *p; +} mem_mapping_t; + +/*Only present on external bus (ISA/PCI)*/ +#define MEM_MAPPING_EXTERNAL 1 +/*Only present on internal bus (RAM)*/ +#define MEM_MAPPING_INTERNAL 2 + +extern uint8_t *ram,*rom; +extern uint8_t romext[32768]; +extern int readlnum,writelnum; +extern int memspeed[11]; +extern int nopageerrors; +extern int cache; +extern int memwaitstate; + +void mem_mapping_add(mem_mapping_t *mapping, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t flags, + void *p); +void mem_mapping_set_handler(mem_mapping_t *mapping, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)); +void mem_mapping_set_p(mem_mapping_t *mapping, void *p); +void mem_mapping_set_addr(mem_mapping_t *mapping, uint32_t base, uint32_t size); +void mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec); +void mem_mapping_disable(mem_mapping_t *mapping); +void mem_mapping_enable(mem_mapping_t *mapping); + +void mem_set_mem_state(uint32_t base, uint32_t size, int state); + +#define MEM_READ_ANY 0x00 +#define MEM_READ_INTERNAL 0x10 +#define MEM_READ_EXTERNAL 0x20 +#define MEM_READ_MASK 0xf0 + +#define MEM_WRITE_ANY 0x00 +#define MEM_WRITE_INTERNAL 0x01 +#define MEM_WRITE_EXTERNAL 0x02 +#define MEM_WRITE_DISABLED 0x03 +#define MEM_WRITE_MASK 0x0f + +extern int mem_a20_alt; +extern int mem_a20_key; +void mem_a20_recalc(); + +uint8_t mem_readb_phys(uint32_t addr); +void mem_writeb_phys(uint32_t addr, uint8_t val); + +uint8_t mem_read_ram(uint32_t addr, void *priv); +uint16_t mem_read_ramw(uint32_t addr, void *priv); +uint32_t mem_read_raml(uint32_t addr, void *priv); + +void mem_write_ram(uint32_t addr, uint8_t val, void *priv); +void mem_write_ramw(uint32_t addr, uint16_t val, void *priv); +void mem_write_raml(uint32_t addr, uint32_t val, void *priv); + +uint8_t mem_read_bios(uint32_t addr, void *priv); +uint16_t mem_read_biosw(uint32_t addr, void *priv); +uint32_t mem_read_biosl(uint32_t addr, void *priv); + +void mem_write_null(uint32_t addr, uint8_t val, void *p); +void mem_write_nullw(uint32_t addr, uint16_t val, void *p); +void mem_write_nulll(uint32_t addr, uint32_t val, void *p); + +FILE *romfopen(char *fn, char *mode); + +mem_mapping_t bios_mapping[8]; +mem_mapping_t bios_high_mapping[8]; + + +typedef struct page_t +{ + void (*write_b)(uint32_t addr, uint8_t val, struct page_t *p); + void (*write_w)(uint32_t addr, uint16_t val, struct page_t *p); + void (*write_l)(uint32_t addr, uint32_t val, struct page_t *p); + + uint8_t *mem; + + struct codeblock_t *block, *block_2; + + /*Head of codeblock tree associated with this page*/ + struct codeblock_t *head; + + uint64_t code_present_mask, dirty_mask; +} page_t; + +extern page_t *pages; + +extern page_t **page_lookup; + +uint32_t mmutranslate_noabrt(uint32_t addr, int rw); + +extern uint32_t get_phys_virt,get_phys_phys; +static inline uint32_t get_phys(uint32_t addr) +{ + if (!((addr ^ get_phys_virt) & ~0xfff)) + return get_phys_phys | (addr & 0xfff); + + get_phys_virt = addr; + + if (!(cr0 >> 31)) + { + get_phys_phys = (addr & rammask) & ~0xfff; + return addr & rammask; + } + + get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff; + return get_phys_phys | (addr & 0xfff); +// return mmutranslatereal(addr, 0) & rammask; +} + +static inline uint32_t get_phys_noabrt(uint32_t addr) +{ + if (!(cr0 >> 31)) + return addr & rammask; + + return mmutranslate_noabrt(addr, 0) & rammask; +} + +void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr); + +extern uint32_t mem_logical_addr; + +void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p); +void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p); +void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p); + +void mem_reset_page_blocks(); + +extern mem_mapping_t ram_low_mapping; + +void mem_remap_top_384k(); + +#endif diff --git a/src/memregs.c b/src/memregs.c new file mode 100644 index 000000000..da3ffd827 --- /dev/null +++ b/src/memregs.c @@ -0,0 +1,30 @@ +/* + 0xE1 and 0xE2 Memory Registers + Used by just about any emulated machine +*/ + +#include "ibm.h" + +#include "io.h" +#include "memregs.h" + +static uint8_t mem_regs[2] = {0xFF, 0xFF}; + +void memregs_write(uint16_t port, uint8_t val, void *priv) +{ + mem_regs[port - 0xE1] = val; +} + +uint8_t memregs_read(uint16_t port, void *priv) +{ + return mem_regs[port - 0xE1]; +} + +void memregs_init() +{ + int i = 0; + + pclog("Memory Registers Init\n"); + + io_sethandler(0x00e1, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); +} diff --git a/src/memregs.h b/src/memregs.h new file mode 100644 index 000000000..1f3baa92a --- /dev/null +++ b/src/memregs.h @@ -0,0 +1 @@ +extern void memregs_init(); diff --git a/src/model.c b/src/model.c new file mode 100644 index 000000000..9124a1981 --- /dev/null +++ b/src/model.c @@ -0,0 +1,618 @@ +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "io.h" + +#include "acer386sx.h" +#include "acerm3a.h" +#include "ali1429.h" +#include "amstrad.h" +#include "compaq.h" +#include "device.h" +#include "dma.h" +#include "fdc.h" +#include "fdc37c665.h" +#include "fdc37c932fr.h" +#include "gameport.h" +#include "headland.h" +#include "i430fx.h" +#include "i430hx.h" +#include "i430lx.h" +#include "i430nx.h" +#include "i430vx.h" +#include "i440fx.h" +#include "ide.h" +#include "intel.h" +#include "intel_flash.h" +#include "jim.h" +#include "keyboard_amstrad.h" +#include "keyboard_at.h" +#include "keyboard_olim24.h" +#include "keyboard_pcjr.h" +#include "keyboard_xt.h" +#include "lpt.h" +#include "memregs.h" +#include "mouse_ps2.h" +#include "mouse_serial.h" +#include "neat.h" +#include "nmi.h" +#include "nvr.h" +#include "olivetti_m24.h" +#include "pc87306.h" +#include "pci.h" +#include "pic.h" +#include "piix.h" +#include "pit.h" +#include "ps1.h" +#include "scat.h" +#include "serial.h" +#include "sis496.h" +#include "sis85c471.h" +#include "sio.h" +#include "sound_ps1.h" +#include "sound_pssj.h" +#include "sound_sn76489.h" +#include "tandy_eeprom.h" +#include "tandy_rom.h" +#include "um8669f.h" +// #include "um8881f.h" +#include "w83877f.h" +#include "wd76c10.h" +#include "xtide.h" + +void xt_init(); +void pcjr_init(); +void tandy1k_init(); +void tandy1ksl2_init(); +void ams_init(); +void europc_init(); +void olim24_init(); +void at_init(); +void deskpro386_init(); +void ps1_m2011_init(); +void ps1_m2121_init(); +void at_neat_init(); +void at_scat_init(); +void at_acer386sx_init(); +void at_wd76c10_init(); +void at_ali1429_init(); +void at_headland_init(); +// void at_um8881f_init(); +void at_sis496_init(); +void at_i430vx_init(); +void at_batman_init(); +void at_endeavor_init(); + +void at_dtk486_init(); +void at_r418_init(); +void at_586mc1_init(); +void at_plato_init(); +void at_mb500n_init(); +void at_p54tp4xe_init(); +void at_acerm3a_init(); +void at_acerv35n_init(); +void at_p55t2p4_init(); +void at_p55tvp4_init(); +void at_p55va_init(); +void at_i440fx_init(); +void at_kn97_init(); + +int model; + +int AMSTRAD, AT, PCI, TANDY; + +int mouse_always_serial; + +MODEL models[] = +{ + {"IBM PC", ROM_IBMPC, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init}, + {"IBM XT", ROM_IBMXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"IBM PCjr", ROM_IBMPCJR, { "", cpus_pcjr, "", NULL, "", NULL}, 1, 0, 128, 640, 128, pcjr_init}, + {"Generic XT clone", ROM_GENXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"AMI XT clone", ROM_AMIXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"DTK XT clone", ROM_DTKXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"VTech Laser Turbo XT",ROM_LTXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"VTech Laser XT3", ROM_LXT3, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"Phoenix XT clone", ROM_PXXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"Juko XT clone", ROM_JUKOPC, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"Tandy 1000", ROM_TANDY, { "", cpus_8088, "", NULL, "", NULL}, 1, 0, 128, 640, 128, tandy1k_init}, + {"Tandy 1000 HX", ROM_TANDY1000HX, { "", cpus_8088, "", NULL, "", NULL}, 1, 0, 256, 640, 128, tandy1k_init}, + {"Tandy 1000 SL/2", ROM_TANDY1000SL2,{ "", cpus_8086, "", NULL, "", NULL}, 1, 0, 512, 768, 128, tandy1ksl2_init}, + {"Amstrad PC1512", ROM_PC1512, { "", cpus_pc1512, "", NULL, "", NULL}, 1, 0, 512, 640, 128, ams_init}, + {"Sinclair PC200", ROM_PC200, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 512, 640, 128, ams_init}, + {"Euro PC", ROM_EUROPC, { "", cpus_8086, "", NULL, "", NULL}, 0, 0, 512, 640, 128, europc_init}, + {"Olivetti M24", ROM_OLIM24, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 128, 640, 128, olim24_init}, + {"Amstrad PC1640", ROM_PC1640, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 640, 640, 0, ams_init}, + {"Amstrad PC2086", ROM_PC2086, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 640, 640, 0, ams_init}, + {"Amstrad PC3086", ROM_PC3086, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 640, 640, 0, ams_init}, + {"IBM AT", ROM_IBMAT, { "", cpus_ibmat, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_init}, + {"Commodore PC 30 III", ROM_CMDPC30, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_init}, + {"AMI 286 clone", ROM_AMI286, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_neat_init}, + {"Award 286 clone", ROM_AWARD286, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_scat_init}, + {"DELL System 200", ROM_DELL200, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_init}, + {"IBM PS/1 model 2011", ROM_IBMPS1_2011, { "", cpus_ps1_m2011,"", NULL, "", NULL}, 1, 1, 1, 16, 1, ps1_m2011_init}, + {"IBM PS/1 model 2121", ROM_IBMPS1_2121, { "Intel", cpus_i386, "", NULL, "", NULL}, 1, 1, 1, 16, 1, ps1_m2121_init}, + {"Compaq Deskpro 386", ROM_DESKPRO_386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 15, 1, deskpro386_init}, + {"Acer 386SX25/N", ROM_ACER386, { "Intel", cpus_acer, "", NULL, "", NULL}, 1, 1, 1, 16, 1, at_acer386sx_init}, + {"DTK 386SX clone", ROM_DTK386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 16, 1, at_neat_init}, + {"Phoenix 386 clone", ROM_PX386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 16, 1, at_init}, + {"Amstrad MegaPC", ROM_MEGAPC, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 1, 1, 1, 16, 1, at_wd76c10_init}, + {"AMI 386 clone", ROM_AMI386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 256, 1, at_headland_init}, + {"AMI 486 clone", ROM_AMI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_ali1429_init}, + {"AMI WinBIOS 486", ROM_WIN486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_ali1429_init}, +/* {"AMI WinBIOS 486 PCI", ROM_PCI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_um8881f_init},*/ + {"DTK PKM-0038S E-2", ROM_DTK486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_dtk486_init}, + {"Award SiS 496/497", ROM_SIS496, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_sis496_init}, + {"Rise Computer R418", ROM_R418, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_r418_init}, + {"Intel Premiere/PCI", ROM_REVENGE, { "Intel", cpus_Pentium5V, "", NULL, "", NULL}, 0, 1, 1, 128, 1, at_batman_init}, + {"Micro Star 586MC1", ROM_586MC1, { "Intel", cpus_Pentium5V50, "",NULL, "", NULL}, 0, 1, 1, 128, 1, at_586mc1_init}, + {"Intel Premiere/PCI II",ROM_PLATO, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, 1, 1, 128, 1, at_plato_init}, + {"Intel Advanced/EV", ROM_ENDEAVOR, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, 1, 1, 128, 1, at_endeavor_init}, + {"PC Partner MB500N", ROM_MB500N, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, 1, 1, 128, 1, at_mb500n_init}, + {"ASUS P/I-P54TP4XE", ROM_P54TP4XE, { "Intel", cpus_PentiumS5, "IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, 1, 1, 512, 1, at_p54tp4xe_init}, + {"Acer M3a", ROM_ACERM3A, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 512, 1, at_acerm3a_init}, + {"Acer V35N", ROM_ACERV35N, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 512, 1, at_acerv35n_init}, + {"ASUS P/I-P55T2P4", ROM_P55T2P4, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 512, 1, at_p55t2p4_init}, + {"Award 430VX PCI", ROM_430VX, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 256, 1, at_i430vx_init}, + {"ASUS P/I-P55TVP4", ROM_P55TVP4, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 512, 1, at_p55tvp4_init}, + {"Epox P55-VA", ROM_P55VA, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 256, 1, at_p55va_init}, + {"Award 440FX PCI", ROM_440FX, { "Intel", cpus_PentiumPro,"Klamath", cpus_Pentium2, "Deschutes", cpus_Pentium2D}, 0, 1, 1, 1024, 1, at_i440fx_init}, + {"Award KN97 (440FX PCI)",ROM_KN97, { "Intel", cpus_PentiumPro,"Klamath", cpus_Pentium2, "Deschutes", cpus_Pentium2D}, 0, 1, 1, 1024, 1, at_kn97_init}, + {"", -1, {"", 0, "", 0, "", 0}, 0,0,0, 0} +}; + +int model_count() +{ + return (sizeof(models) / sizeof(MODEL)) - 1; +} + +int model_getromset() +{ + return models[model].id; +} + +int model_getmodel(int romset) +{ + int c = 0; + + while (models[c].id != -1) + { + if (models[c].id == romset) + return c; + c++; + } + + return 0; +} + +char *model_getname() +{ + return models[model].name; +} + +void common_init() +{ + dma_init(); + fdc_add(); + lpt_init(); + pic_init(); + pit_init(); + serial1_init(0x3f8, 4); + serial2_init(0x2f8, 3); +} + +void xt_init() +{ + common_init(); + mem_add_bios(); + pit_set_out_func(1, pit_refresh_timer_xt); + keyboard_xt_init(); + mouse_serial_init(); + xtide_init(); + nmi_init(); + device_add(&gameport_device); +} + +void pcjr_init() +{ + mem_add_bios(); + fdc_add_pcjr(); + pic_init(); + pit_init(); + pit_set_out_func(0, pit_irq0_timer_pcjr); + serial1_init(0x2f8, 3); + keyboard_pcjr_init(); + device_add(&sn76489_device); + nmi_mask = 0x80; +} + +void tandy1k_init() +{ + TANDY = 1; + common_init(); + mem_add_bios(); + keyboard_tandy_init(); + mouse_serial_init(); + if (romset == ROM_TANDY) + device_add(&sn76489_device); + else + device_add(&ncr8496_device); + xtide_init(); + nmi_init(); + if (romset != ROM_TANDY) + device_add(&tandy_eeprom_device); + device_add(&gameport_device); +} +void tandy1ksl2_init() +{ +// TANDY = 1; + common_init(); + mem_add_bios(); + keyboard_tandy_init(); + mouse_serial_init(); + device_add(&pssj_device); + xtide_init(); + nmi_init(); + device_add(&tandy_rom_device); + device_add(&tandy_eeprom_device); + device_add(&gameport_device); +} + +void ams_init() +{ + AMSTRAD = 1; + common_init(); + mem_add_bios(); + amstrad_init(); + keyboard_amstrad_init(); + nvr_init(); + xtide_init(); + nmi_init(); + fdc_set_dskchg_activelow(); + device_add(&gameport_device); +} + +void europc_init() +{ + common_init(); + mem_add_bios(); + jim_init(); + keyboard_xt_init(); + mouse_serial_init(); + xtide_init(); + nmi_init(); + device_add(&gameport_device); +} + +void olim24_init() +{ + common_init(); + mem_add_bios(); + keyboard_olim24_init(); + nvr_init(); + olivetti_m24_init(); + xtide_init(); + nmi_init(); + device_add(&gameport_device); +} + +void at_init() +{ + AT = 1; + common_init(); + lpt2_remove(); + mem_add_bios(); + pit_set_out_func(1, pit_refresh_timer_at); + dma16_init(); + ide_init(); + keyboard_at_init(); + if (models[model].init == at_init) + mouse_serial_init(); + nvr_init(); + pic2_init(); + device_add(&gameport_device); +} + +void deskpro386_init() +{ + at_init(); + mouse_serial_init(); + compaq_init(); +} + +void ps1_common_init() +{ + AT = 1; + common_init(); + mem_add_bios(); + pit_set_out_func(1, pit_refresh_timer_at); + dma16_init(); + ide_init(); + keyboard_at_init(); + mouse_ps2_init(); + nvr_init(); + pic2_init(); + fdc_set_dskchg_activelow(); + device_add(&ps1_audio_device); + /*PS/1 audio uses ports 200h and 202-207h, so only initialise gameport on 201h*/ + device_add(&gameport_201_device); +} + +void ps1_m2011_init() +{ + ps1_common_init(); + ps1mb_init(); +} + +void ps1_m2121_init() +{ + ps1_common_init(); + ps1mb_m2121_init(); + fdc_set_ps1(); +} + +void at_neat_init() +{ + at_init(); + mouse_serial_init(); + neat_init(); +} + +void at_scat_init() +{ + at_init(); + mouse_serial_init(); + scat_init(); +} + +void at_acer386sx_init() +{ + at_init(); + mouse_ps2_init(); + acer386sx_init(); +} + +void at_wd76c10_init() +{ + at_init(); + mouse_ps2_init(); + wd76c10_init(); +} + +void at_headland_init() +{ + at_init(); + headland_init(); + mouse_serial_init(); +} + +void at_ali1429_init() +{ + at_init(); + ali1429_init(); + mouse_serial_init(); + if (cdrom_channel <= 1) ide_sec_disable(); +} + +/* void at_um8881f_init() +{ + at_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + um8881f_init(); +} */ + +void at_dtk486_init() +{ + at_init(); + memregs_init(); + mouse_serial_init(); + sis85c471_init(); + if (cdrom_channel <= 1) ide_sec_disable(); +} + +void at_sis496_init() +{ + at_init(); + memregs_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + device_add(&sis496_device); + ide_ter_init(); +} + +void at_r418_init() +{ + at_init(); + memregs_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + fdc37c665_init(); + device_add(&sis496_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_batman_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_2, 0xd, 0x10); + i430lx_init(); + sio_init(1); + fdc37c665_init(); + intel_batman_init(); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_586mc1_init() +{ + at_init(); + memregs_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_2, 0xd, 0x10); + i430lx_init(); + sio_init(1); + device_add(&intel_flash_bxt_device); + if (cdrom_channel <= 1) ide_sec_disable(); +} + +void at_plato_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_2, 0xd, 0x10); + i430nx_init(); + sio_init(1); + fdc37c665_init(); + /* It seems it uses the same interface as Batman. */ + intel_batman_init(); + // device_add(&intel_flash_bxt_ami_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_endeavor_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430fx_init(); + piix_init(7); + pc87306_init(); + intel_endeavor_init(); + device_add(&intel_flash_bxt_ami_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_mb500n_init() +{ + at_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430fx_init(); + piix_init(7); + fdc37c665_init(); + intel_endeavor_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_p54tp4xe_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430fx_init(); + piix_init(7); + fdc37c665_init(); + intel_endeavor_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_acerm3a_init() +{ + at_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430hx_init(); + piix3_init(7); + fdc37c932fr_init(); + acerm3a_io_init(); + device_add(&intel_flash_bxb_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_acerv35n_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430hx_init(); + piix3_init(7); + fdc37c932fr_init(); + acerm3a_io_init(); + device_add(&intel_flash_bxb_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_p55t2p4_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i430hx_init(); + piix3_init(7); + w83877f_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_i430vx_init() +{ + at_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i430vx_init(); + piix3_init(7); + um8669f_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_p55tvp4_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i430vx_init(); + piix3_init(7); + w83877f_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_p55va_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i430vx_init(); + piix3_init(7); + fdc37c932fr_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_i440fx_init() +{ + at_init(); + mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i440fx_init(); + piix3_init(7); + fdc37c665_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_kn97_init() +{ + at_init(); + mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i440fx_init(); + piix3_init(7); + w83877f_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void model_init() +{ + pclog("Initting as %s\n", model_getname()); + AMSTRAD = AT = PCI = TANDY = 0; + io_init(); + + fdc_update_is_nsc(0); + models[model].init(); +} diff --git a/src/model.h b/src/model.h new file mode 100644 index 000000000..ce5d6a2b8 --- /dev/null +++ b/src/model.h @@ -0,0 +1,25 @@ +typedef struct +{ + char name[24]; + int id; + struct + { + char name[16]; + CPU *cpus; + } cpu[5]; + int fixed_gfxcard; + int is_at; + int min_ram, max_ram; + int ram_granularity; + void (*init)(); +} MODEL; + +extern MODEL models[]; + +extern int model; + +int model_count(); +int model_getromset(); +int model_getmodel(int romset); +char *model_getname(); +void model_init(); diff --git a/src/mouse.c b/src/mouse.c new file mode 100644 index 000000000..32c49ed0b --- /dev/null +++ b/src/mouse.c @@ -0,0 +1,4 @@ +#include "ibm.h" +#include "mouse.h" + +void (*mouse_poll)(int x, int y, int b); diff --git a/src/mouse.h b/src/mouse.h new file mode 100644 index 000000000..04f17a6d7 --- /dev/null +++ b/src/mouse.h @@ -0,0 +1,5 @@ +extern void (*mouse_poll)(int x, int y, int b); + +extern int mousepos; +extern int mousedelay; + diff --git a/src/mouse_ps2.c b/src/mouse_ps2.c new file mode 100644 index 000000000..e5cd3d670 --- /dev/null +++ b/src/mouse_ps2.c @@ -0,0 +1,189 @@ +#include "ibm.h" +#include "keyboard_at.h" +#include "mouse.h" +#include "mouse_ps2.h" +#include "plat-mouse.h" + +int mouse_scan = 0; + +enum +{ + MOUSE_STREAM, + MOUSE_REMOTE, + MOUSE_ECHO +}; + +#define MOUSE_ENABLE 0x20 +#define MOUSE_SCALE 0x10 + +static struct +{ + int mode; + + uint8_t flags; + uint8_t resolution; + uint8_t sample_rate; + uint8_t type; + + uint8_t command; + + int cd; +} mouse_ps2; + +void mouse_ps2_write(uint8_t val) +{ + // pclog("PS/2 Mouse: Write %02X\n", val); + + if (mouse_ps2.cd) + { + mouse_ps2.cd = 0; + switch (mouse_ps2.command) + { + case 0xe8: /*Set mouse resolution*/ + mouse_ps2.resolution = val; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf3: /*Set sample rate*/ + mouse_ps2.sample_rate = val; + keyboard_at_adddata_mouse(0xfa); + break; + +// default: +// fatal("mouse_ps2 : Bad data write %02X for command %02X\n", val, mouse_ps2.command); + } + } + else + { + uint8_t temp; + + mouse_ps2.command = val; + switch (mouse_ps2.command) + { + case 0xe6: /*Set scaling to 1:1*/ + mouse_ps2.flags &= ~MOUSE_SCALE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe7: /*Set scaling to 2:1*/ + mouse_ps2.flags |= MOUSE_SCALE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe8: /*Set mouse resolution*/ + mouse_ps2.cd = 1; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe9: /*Status request*/ + keyboard_at_adddata_mouse(0xfa); + temp = mouse_ps2.flags; + if (mouse_buttons & 1) + temp |= 1; + if (mouse_buttons & 2) + temp |= 2; + if (mouse_buttons & 4) + temp |= 3; + keyboard_at_adddata_mouse(temp); + keyboard_at_adddata_mouse(mouse_ps2.resolution); + keyboard_at_adddata_mouse(mouse_ps2.sample_rate); + break; + + case 0xf2: /*Read ID*/ + keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse(0x00); + break; + + case 0xf3: /*Set sample rate*/ + mouse_ps2.cd = 1; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf4: /*Enable*/ + mouse_ps2.flags |= MOUSE_ENABLE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf5: /*Disable*/ + mouse_ps2.flags &= ~MOUSE_ENABLE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xff: /*Reset*/ + mouse_ps2.mode = MOUSE_STREAM; + mouse_ps2.flags = 0; + keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse(0xaa); + keyboard_at_adddata_mouse(0x00); + break; + +// default: +// fatal("mouse_ps2 : Bad command %02X\n", val, mouse_ps2.command); + } + } +} + +static int ps2_x = 0, ps2_y = 0, ps2_b = 0; +int first_time = 1; +void mouse_ps2_poll(int x, int y, int b) +{ + uint8_t packet[3] = {0x08, 0, 0}; + if (!x && !y && b == ps2_b && !first_time){ + // pclog("PS/2 Mouse: X is 0, Y is 0, and B is PS2_B\n"); + return; + } + + if (first_time) first_time = 0; + + if (!mouse_scan) + { + // pclog("PS/2 Mouse: Not scanning\n"); + return; + } + ps2_x += x; + ps2_y -= y; + if (mouse_ps2.mode == MOUSE_STREAM && (mouse_ps2.flags & MOUSE_ENABLE) && + ((mouse_queue_end - mouse_queue_start) & 0xf) < 13) + { + ps2_b = b; + // pclog("Send packet : %i %i\n", ps2_x, ps2_y); + if (ps2_x > 255) + ps2_x = 255; + if (ps2_x < -256) + ps2_x = -256; + if (ps2_y > 255) + ps2_y = 255; + if (ps2_y < -256) + ps2_y = -256; + if (ps2_x < 0) + packet[0] |= 0x10; + if (ps2_y < 0) + packet[0] |= 0x20; + if (mouse_buttons & 1) + packet[0] |= 1; + if (mouse_buttons & 2) + packet[0] |= 2; + if (mouse_buttons & 4) + packet[0] |= 4; + packet[1] = ps2_x & 0xff; + packet[2] = ps2_y & 0xff; + + ps2_x = ps2_y = 0; + + keyboard_at_adddata_mouse(packet[0]); + keyboard_at_adddata_mouse(packet[1]); + keyboard_at_adddata_mouse(packet[2]); + } + + // pclog("PS/2 Mouse: Poll\n"); +} + + +void mouse_ps2_init() +{ + mouse_poll = mouse_ps2_poll; + mouse_write = mouse_ps2_write; + mouse_ps2.cd = 0; + mouse_ps2.flags = 0; + mouse_ps2.mode = MOUSE_STREAM; +} diff --git a/src/mouse_ps2.h b/src/mouse_ps2.h new file mode 100644 index 000000000..95294df35 --- /dev/null +++ b/src/mouse_ps2.h @@ -0,0 +1 @@ +void mouse_ps2_init(); diff --git a/src/mouse_serial.c b/src/mouse_serial.c new file mode 100644 index 000000000..b5eeb1547 --- /dev/null +++ b/src/mouse_serial.c @@ -0,0 +1,72 @@ +#include "ibm.h" +#include "mouse.h" +#include "pic.h" +#include "serial.h" +#include "timer.h" + +static int oldb=0; + +void mouse_serial_poll(int x, int y, int b) +{ + uint8_t mousedat[3]; + + if (!(serial1.ier & 1)) + return; + if (!x && !y && b==oldb) return; + + oldb=b; + if (x>127) x=127; + if (y>127) y=127; + if (x<-128) x=-128; + if (y<-128) y=-128; + + /*Use Microsoft format*/ + mousedat[0]=0x40; + mousedat[0]|=(((y>>6)&3)<<2); + mousedat[0]|=((x>>6)&3); + if (b&1) mousedat[0]|=0x20; + if (b&2) mousedat[0]|=0x10; + mousedat[1]=x&0x3F; + mousedat[2]=y&0x3F; + + if (!(serial1.mctrl&0x10)) + { + pclog("Serial data %02X %02X %02X\n", mousedat[0], mousedat[1], mousedat[2]); + serial_write_fifo(&serial1, mousedat[0]); + serial_write_fifo(&serial1, mousedat[1]); + serial_write_fifo(&serial1, mousedat[2]); + } +} + +void mouse_serial_rcr(void *p) +{ + mousepos=-1; + mousedelay=5000 * (1 << TIMER_SHIFT); +} + +void mousecallback(void *p) +{ + SERIAL *serial = (SERIAL *)p; + mousedelay = 0; + if (mousepos == -1) + { + mousepos = 0; +/* serial_fifo_read = serial_fifo_write = 0; + serial.lsr &= ~1;*/ + serial_write_fifo(serial, 'M'); + } +/* else if (serial_fifo_read != serial_fifo_write) + { + serial.iir=4; + serial.lsr|=1; + if (serial.mctrl&8) picint(0x10); + }*/ +} + +void mouse_serial_init() +{ + mouse_poll = mouse_serial_poll; + serial1.rcr_callback = mouse_serial_rcr; + timer_add(mousecallback, &mousedelay, &mousedelay, &serial1); +} + diff --git a/src/mouse_serial.h b/src/mouse_serial.h new file mode 100644 index 000000000..22b7f3830 --- /dev/null +++ b/src/mouse_serial.h @@ -0,0 +1 @@ +void mouse_serial_init(); diff --git a/src/ne2000.c b/src/ne2000.c new file mode 100644 index 000000000..24321ae22 --- /dev/null +++ b/src/ne2000.c @@ -0,0 +1,2128 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 MandrakeSoft S.A. +// +// MandrakeSoft S.A. +// 43, rue d'Aboukir +// 75002 Paris - France +// http://www.linux-mandrake.com/ +// http://www.mandrakesoft.com/ +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +// Peter Grehan (grehan@iprg.nokia.com) coded all of this +// NE2000/ether stuff. +//#include "vl.h" +#include +#include +#include +#include + +#include "slirp/slirp.h" +#include "slirp/queue.h" +#include + +#include "ibm.h" +#include "device.h" + +#include "nethandler.h" + +#include "io.h" +#include "mem.h" +#include "nethandler.h" +#include "rom.h" + +#include "ne2000.h" +#include "pci.h" +#include "pic.h" +#include "timer.h" + +//THIS IS THE DEFAULT MAC ADDRESS .... so it wont place nice with multiple VMs. YET. +uint8_t maclocal[6] = {0xac, 0xde, 0x48, 0x88, 0xbb, 0xaa}; + +#define NETBLOCKING 0 //we won't block our pcap + +static HINSTANCE net_hLib = 0; /* handle to DLL */ +static char* net_lib_name = "wpcap.dll"; +pcap_t *net_pcap; +typedef pcap_t* (__cdecl * PCAP_OPEN_LIVE)(const char *, int, int, int, char *); +typedef int (__cdecl * PCAP_SENDPACKET)(pcap_t* handle, const u_char* msg, int len); +typedef int (__cdecl * PCAP_SETNONBLOCK)(pcap_t *, int, char *); +typedef const u_char*(__cdecl *PCAP_NEXT)(pcap_t *, struct pcap_pkthdr *); +typedef const char*(__cdecl *PCAP_LIB_VERSION)(void); +typedef void (__cdecl *PCAP_CLOSE)(pcap_t *); +typedef int (__cdecl *PCAP_GETNONBLOCK)(pcap_t *p, char *errbuf); +typedef int (__cdecl *PCAP_COMPILE)(pcap_t *p, struct bpf_program *fp, const char *str, int optimize, bpf_u_int32 netmask); +typedef int (__cdecl *PCAP_SETFILTER)(pcap_t *p, struct bpf_program *fp); + +PCAP_LIB_VERSION _pcap_lib_version; +PCAP_OPEN_LIVE _pcap_open_live; +PCAP_SENDPACKET _pcap_sendpacket; +PCAP_SETNONBLOCK _pcap_setnonblock; +PCAP_NEXT _pcap_next; +PCAP_CLOSE _pcap_close; +PCAP_GETNONBLOCK _pcap_getnonblock; +PCAP_COMPILE _pcap_compile; +PCAP_SETFILTER _pcap_setfilter; + +queueADT slirpq; +int net_slirp_inited=0; +int net_is_slirp=1; //by default we go with slirp +int net_is_pcap=0; //and pretend pcap is dead. +int fizz=0; +void slirp_tic(); + +#define BX_RESET_HARDWARE 0 +#define BX_RESET_SOFTWARE 1 + +//Never completely fill the ne2k ring so that we never +// hit the unclear completely full buffer condition. +#define BX_NE2K_NEVER_FULL_RING (1) + +#define BX_NE2K_MEMSIZ (32*1024) +#define BX_NE2K_MEMSTART (16*1024) +#define BX_NE2K_MEMEND (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ) + +uint8_t rtl8029as_eeprom[128]; + +typedef struct ne2000_t +{ + // + // ne2k register state + + // + // Page 0 + // + // Command Register - 00h read/write + struct CR_t { + int stop; // STP - Software Reset command + int start; // START - start the NIC + int tx_packet; // TXP - initiate packet transmission + uint8_t rdma_cmd; // RD0,RD1,RD2 - Remote DMA command + uint8_t pgsel; // PS0,PS1 - Page select + } CR; + // Interrupt Status Register - 07h read/write + struct ISR_t { + int pkt_rx; // PRX - packet received with no errors + int pkt_tx; // PTX - packet transmitted with no errors + int rx_err; // RXE - packet received with 1 or more errors + int tx_err; // TXE - packet tx'd " " " " " + int overwrite; // OVW - rx buffer resources exhausted + int cnt_oflow; // CNT - network tally counter MSB's set + int rdma_done; // RDC - remote DMA complete + int reset; // RST - reset status + } ISR; + // Interrupt Mask Register - 0fh write + struct IMR_t { + int rx_inte; // PRXE - packet rx interrupt enable + int tx_inte; // PTXE - packet tx interrput enable + int rxerr_inte; // RXEE - rx error interrupt enable + int txerr_inte; // TXEE - tx error interrupt enable + int overw_inte; // OVWE - overwrite warn int enable + int cofl_inte; // CNTE - counter o'flow int enable + int rdma_inte; // RDCE - remote DMA complete int enable + int reserved; // D7 - reserved + } IMR; + // Data Configuration Register - 0eh write + struct DCR_t { + int wdsize; // WTS - 8/16-bit select + int endian; // BOS - byte-order select + int longaddr; // LAS - long-address select + int loop; // LS - loopback select + int auto_rx; // AR - auto-remove rx packets with remote DMA + uint8_t fifo_size; // FT0,FT1 - fifo threshold + } DCR; + // Transmit Configuration Register - 0dh write + struct TCR_t { + int crc_disable; // CRC - inhibit tx CRC + uint8_t loop_cntl; // LB0,LB1 - loopback control + int ext_stoptx; // ATD - allow tx disable by external mcast + int coll_prio; // OFST - backoff algorithm select + uint8_t reserved; // D5,D6,D7 - reserved + } TCR; + // Transmit Status Register - 04h read + struct TSR_t { + int tx_ok; // PTX - tx complete without error + int reserved; // D1 - reserved + int collided; // COL - tx collided >= 1 times + int aborted; // ABT - aborted due to excessive collisions + int no_carrier; // CRS - carrier-sense lost + int fifo_ur; // FU - FIFO underrun + int cd_hbeat; // CDH - no tx cd-heartbeat from transceiver + int ow_coll; // OWC - out-of-window collision + } TSR; + // Receive Configuration Register - 0ch write + struct RCR_t { + int errors_ok; // SEP - accept pkts with rx errors + int runts_ok; // AR - accept < 64-byte runts + int broadcast; // AB - accept eth broadcast address + int multicast; // AM - check mcast hash array + int promisc; // PRO - accept all packets + int monitor; // MON - check pkts, but don't rx + uint8_t reserved; // D6,D7 - reserved + } RCR; + // Receive Status Register - 0ch read + struct RSR_t { + int rx_ok; // PRX - rx complete without error + int bad_crc; // CRC - Bad CRC detected + int bad_falign; // FAE - frame alignment error + int fifo_or; // FO - FIFO overrun + int rx_missed; // MPA - missed packet error + int rx_mbit; // PHY - unicast or mcast/bcast address match + int rx_disabled; // DIS - set when in monitor mode + int deferred; // DFR - collision active + } RSR; + + uint16_t local_dma; // 01,02h read ; current local DMA addr + uint8_t page_start; // 01h write ; page start register + uint8_t page_stop; // 02h write ; page stop register + uint8_t bound_ptr; // 03h read/write ; boundary pointer + uint8_t tx_page_start; // 04h write ; transmit page start register + uint8_t num_coll; // 05h read ; number-of-collisions register + uint16_t tx_bytes; // 05,06h write ; transmit byte-count register + uint8_t fifo; // 06h read ; FIFO + uint16_t remote_dma; // 08,09h read ; current remote DMA addr + uint16_t remote_start; // 08,09h write ; remote start address register + uint16_t remote_bytes; // 0a,0bh write ; remote byte-count register + uint8_t tallycnt_0; // 0dh read ; tally counter 0 (frame align errors) + uint8_t tallycnt_1; // 0eh read ; tally counter 1 (CRC errors) + uint8_t tallycnt_2; // 0fh read ; tally counter 2 (missed pkt errors) + + uint8_t i8029id0; + uint8_t i8029id1; + + // + // Page 1 + // + // Command Register 00h (repeated) + // + uint8_t physaddr[6]; // 01-06h read/write ; MAC address + uint8_t curr_page; // 07h read/write ; current page register + uint8_t mchash[8]; // 08-0fh read/write ; multicast hash array + + // + // Page 2 - diagnostic use only + // + // Command Register 00h (repeated) + // + // Page Start Register 01h read (repeated) + // Page Stop Register 02h read (repeated) + // Current Local DMA Address 01,02h write (repeated) + // Transmit Page start address 04h read (repeated) + // Receive Configuration Register 0ch read (repeated) + // Transmit Configuration Register 0dh read (repeated) + // Data Configuration Register 0eh read (repeated) + // Interrupt Mask Register 0fh read (repeated) + // + uint8_t rempkt_ptr; // 03h read/write ; remote next-packet pointer + uint8_t localpkt_ptr; // 05h read/write ; local next-packet pointer + uint16_t address_cnt; // 06,07h read/write ; address counter + + // + // Page 3 - should never be modified. + // + uint8_t cr; + uint8_t i9346cr; + uint8_t config0; + uint8_t config2; + uint8_t config3; + uint8_t hltclk; + uint8_t i8029asid0; + uint8_t i8029asid1; + + // Novell ASIC state + uint8_t macaddr[32]; // ASIC ROM'd MAC address, even bytes + uint8_t mem[BX_NE2K_MEMSIZ]; // on-chip packet memory + + // ne2k internal state + uint32_t base_address; + int base_irq; + int tx_timer_index; + int tx_timer_active; + + rom_t bios_rom; + +} ne2000_t; + +int disable_netbios = 0; + +static void ne2000_tx_event(int val, void *p); + +void ne2000_rx_frame(void *p, const void *buf, int io_len); + +static void ne2000_setirq(ne2000_t *ne2000, int irq) +{ + ne2000->base_irq = irq; +} +// +// reset - restore state to power-up, cancelling all i/o +// +static void ne2000_reset(int type, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("ne2000 reset\n"); + + int i; + + // Initialise the mac address area by doubling the physical address + ne2000->macaddr[0] = ne2000->physaddr[0]; + ne2000->macaddr[1] = ne2000->physaddr[0]; + ne2000->macaddr[2] = ne2000->physaddr[1]; + ne2000->macaddr[3] = ne2000->physaddr[1]; + ne2000->macaddr[4] = ne2000->physaddr[2]; + ne2000->macaddr[5] = ne2000->physaddr[2]; + ne2000->macaddr[6] = ne2000->physaddr[3]; + ne2000->macaddr[7] = ne2000->physaddr[3]; + ne2000->macaddr[8] = ne2000->physaddr[4]; + ne2000->macaddr[9] = ne2000->physaddr[4]; + ne2000->macaddr[10] = ne2000->physaddr[5]; + ne2000->macaddr[11] = ne2000->physaddr[5]; + + // ne2k signature + for (i = 12; i < 32; i++) + ne2000->macaddr[i] = 0x57; + + // Zero out registers and memory + memset( & ne2000->CR, 0, sizeof(ne2000->CR) ); + memset( & ne2000->ISR, 0, sizeof(ne2000->ISR)); + memset( & ne2000->IMR, 0, sizeof(ne2000->IMR)); + memset( & ne2000->DCR, 0, sizeof(ne2000->DCR)); + memset( & ne2000->TCR, 0, sizeof(ne2000->TCR)); + memset( & ne2000->TSR, 0, sizeof(ne2000->TSR)); + //memset( & ne2000->RCR, 0, sizeof(ne2000->RCR)); + memset( & ne2000->RSR, 0, sizeof(ne2000->RSR)); + ne2000->tx_timer_active = 0; + ne2000->local_dma = 0; + ne2000->page_start = 0; + ne2000->page_stop = 0; + ne2000->bound_ptr = 0; + ne2000->tx_page_start = 0; + ne2000->num_coll = 0; + ne2000->tx_bytes = 0; + ne2000->fifo = 0; + ne2000->remote_dma = 0; + ne2000->remote_start = 0; + ne2000->remote_bytes = 0; + ne2000->tallycnt_0 = 0; + ne2000->tallycnt_1 = 0; + ne2000->tallycnt_2 = 0; + + //memset( & ne2000->physaddr, 0, sizeof(ne2000->physaddr)); + //memset( & ne2000->mchash, 0, sizeof(ne2000->mchash)); + ne2000->curr_page = 0; + + ne2000->rempkt_ptr = 0; + ne2000->localpkt_ptr = 0; + ne2000->address_cnt = 0; + + memset( & ne2000->mem, 0, sizeof(ne2000->mem)); + + // Set power-up conditions + ne2000->CR.stop = 1; + ne2000->CR.rdma_cmd = 4; + ne2000->ISR.reset = 1; + ne2000->DCR.longaddr = 1; + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + //DEV_pic_lower_irq(ne2000->base_irq); +} + +#include "bswap.h" + +// +// chipmem_read/chipmem_write - access the 64K private RAM. +// The ne2000 memory is accessed through the data port of +// the asic (offset 0) after setting up a remote-DMA transfer. +// Both byte and word accesses are allowed. +// The first 16 bytes contains the MAC address at even locations, +// and there is 16K of buffer memory starting at 16K +// +static inline uint8_t ne2000_chipmem_read_b(uint32_t address, ne2000_t *ne2000) +{ + // ROM'd MAC address +if ((address >=0) && (address <= 31)) { + return ne2000->macaddr[address]; + } + + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { + return ne2000->mem[address - BX_NE2K_MEMSTART]; + } else { + return (0xff); + } +} + + +static inline uint16_t ne2000_chipmem_read_w(uint32_t address, ne2000_t *ne2000) +{ + // ROM'd MAC address + if ((address >=0) && (address <= 31)) { + return le16_to_cpu(*(uint16_t *)(ne2000->macaddr + address)); + } + + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { + return le16_to_cpu(*(uint16_t *)(ne2000->mem + (address - BX_NE2K_MEMSTART))); + } else { + return (0xffff); + } +} + +static inline void ne2000_chipmem_write_b(uint32_t address, uint8_t value, ne2000_t *ne2000) +{ + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { + ne2000->mem[address - BX_NE2K_MEMSTART] = value & 0xff; + } +} + + +static inline void ne2000_chipmem_write_w(uint32_t address, uint16_t value, ne2000_t *ne2000) +{ + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { + *(uint16_t *)(ne2000->mem + (address - BX_NE2K_MEMSTART)) = cpu_to_le16(value); + } +} + +// +// asic_read/asic_write - This is the high 16 bytes of i/o space +// (the lower 16 bytes is for the DS8390). Only two locations +// are used: offset 0, which is used for data transfer, and +// offset 0xf, which is used to reset the device. +// The data transfer port is used to as 'external' DMA to the +// DS8390. The chip has to have the DMA registers set up, and +// after that, insw/outsw instructions can be used to move +// the appropriate number of bytes to/from the device. +// +uint16_t ne2000_dma_read(int io_len, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + // + // The 8390 bumps the address and decreases the byte count + // by the selected word size after every access, not by + // the amount of data requested by the host (io_len). + // + ne2000->remote_dma += io_len; + if (ne2000->remote_dma == ne2000->page_stop << 8) { + ne2000->remote_dma = ne2000->page_start << 8; + } + // keep s.remote_bytes from underflowing + if (ne2000->remote_bytes > 1) + ne2000->remote_bytes -= io_len; + else + ne2000->remote_bytes = 0; + + // If all bytes have been written, signal remote-DMA complete + if (ne2000->remote_bytes == 0) { + ne2000->ISR.rdma_done = 1; + if (ne2000->IMR.rdma_inte) { + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } + } + return (0); +} + +uint16_t ne2000_asic_read_w(uint32_t offset, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + int retval; + + if (ne2000->DCR.wdsize & 0x01) { + /* 16 bit access */ + retval = ne2000_chipmem_read_w(ne2000->remote_dma, ne2000); + ne2000_dma_read(2, ne2000); + } else { + /* 8 bit access */ + retval = ne2000_chipmem_read_b(ne2000->remote_dma, ne2000); + ne2000_dma_read(1, ne2000); + } + + pclog("asic read val=0x%04x\n", retval); + + return retval; +} + +void ne2000_dma_write(int io_len, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + // is this right ??? asic_read uses DCR.wordsize + ne2000->remote_dma += io_len; + if (ne2000->remote_dma == ne2000->page_stop << 8) { + ne2000->remote_dma = ne2000->page_start << 8; + } + + ne2000->remote_bytes -= io_len; + if (ne2000->remote_bytes > BX_NE2K_MEMSIZ) + ne2000->remote_bytes = 0; + + // If all bytes have been written, signal remote-DMA complete + if (ne2000->remote_bytes == 0) { + ne2000->ISR.rdma_done = 1; + if (ne2000->IMR.rdma_inte) { + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } + } +} + +void ne2000_asic_write_w(uint32_t offset, uint16_t value, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("asic write val=0x%04x\n", value); + + if (ne2000->remote_bytes == 0) + return; + if (ne2000->DCR.wdsize & 0x01) { + /* 16 bit access */ + ne2000_chipmem_write_w(ne2000->remote_dma, value, ne2000); + ne2000_dma_write(2, ne2000); + } else { + /* 8 bit access */ + ne2000_chipmem_write_b(ne2000->remote_dma, value, ne2000); + ne2000_dma_write(1, ne2000); + } +} + +uint8_t ne2000_asic_read_b(uint32_t offset, void *p) +{ + if (offset & 1) + return ne2000_asic_read_w(offset & ~1, p) >> 1; + return ne2000_asic_read_w(offset, p) & 0xff; +} + +void ne2000_asic_write_b(uint32_t offset, uint8_t value, void *p) +{ + if (offset & 1) + ne2000_asic_write_w(offset & ~1, value << 8, p); + else + ne2000_asic_write_w(offset, value, p); +} + +uint16_t ne2000_reset_read(uint32_t offset, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + ne2000_reset(BX_RESET_SOFTWARE, ne2000); + return 0; +} + +void ne2000_reset_write(uint32_t offset, uint16_t value, void *p) +{ +} + +// +// read_handler/read - i/o 'catcher' function called from BOCHS +// mainline when the CPU attempts a read in the i/o space registered +// by this ne2000 instance +// +uint16_t ne2000_read(uint32_t address, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("read addr %x\n", address); + int ret; + + address &= 0xf; + + if (address == 0x00) { + ret = + (((ne2000->CR.pgsel & 0x03) << 6) | + ((ne2000->CR.rdma_cmd & 0x07) << 3) | + (ne2000->CR.tx_packet << 2) | + (ne2000->CR.start << 1) | + (ne2000->CR.stop)); + pclog("read CR returns 0x%08x\n", ret); + } else { + switch (ne2000->CR.pgsel) { + case 0x00: + pclog("page 0 read from port %04x\n", address); + + switch (address) { + case 0x1: // CLDA0 + return (ne2000->local_dma & 0xff); + break; + + case 0x2: // CLDA1 + return (ne2000->local_dma >> 8); + break; + + case 0x3: // BNRY + return (ne2000->bound_ptr); + break; + + case 0x4: // TSR + return ((ne2000->TSR.ow_coll << 7) | + (ne2000->TSR.cd_hbeat << 6) | + (ne2000->TSR.fifo_ur << 5) | + (ne2000->TSR.no_carrier << 4) | + (ne2000->TSR.aborted << 3) | + (ne2000->TSR.collided << 2) | + (ne2000->TSR.tx_ok)); + break; + + case 0x5: // NCR + return (ne2000->num_coll); + break; + + case 0x6: // FIFO + // reading FIFO is only valid in loopback mode + pclog("reading FIFO not supported yet\n"); + return (ne2000->fifo); + break; + + case 0x7: // ISR + return ((ne2000->ISR.reset << 7) | + (ne2000->ISR.rdma_done << 6) | + (ne2000->ISR.cnt_oflow << 5) | + (ne2000->ISR.overwrite << 4) | + (ne2000->ISR.tx_err << 3) | + (ne2000->ISR.rx_err << 2) | + (ne2000->ISR.pkt_tx << 1) | + (ne2000->ISR.pkt_rx)); + break; + + case 0x8: // CRDA0 + return (ne2000->remote_dma & 0xff); + break; + + case 0x9: // CRDA1 + return (ne2000->remote_dma >> 8); + break; + + case 0xa: // reserved + pclog("reserved read - page 0, 0xa\n"); + if (network_card_current == 2) return ne2000->i8029id0; + return (0xff); + break; + + case 0xb: // reserved + pclog("reserved read - page 0, 0xb\n"); + if (network_card_current == 2) return ne2000->i8029id1; + return (0xff); + break; + + case 0xc: // RSR + return ((ne2000->RSR.deferred << 7) | + (ne2000->RSR.rx_disabled << 6) | + (ne2000->RSR.rx_mbit << 5) | + (ne2000->RSR.rx_missed << 4) | + (ne2000->RSR.fifo_or << 3) | + (ne2000->RSR.bad_falign << 2) | + (ne2000->RSR.bad_crc << 1) | + (ne2000->RSR.rx_ok)); + break; + + case 0xd: // CNTR0 + return (ne2000->tallycnt_0); + break; + + case 0xe: // CNTR1 + return (ne2000->tallycnt_1); + break; + + case 0xf: // CNTR2 + return (ne2000->tallycnt_2); + break; + } + + return(0); + break; + + case 0x01: + pclog("page 1 read from port %04x\n", address); + + switch (address) { + case 0x1: // PAR0-5 + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + return (ne2000->physaddr[address - 1]); + break; + + case 0x7: // CURR + pclog("returning current page: %02x\n", (ne2000->curr_page)); + return (ne2000->curr_page); + + case 0x8: // MAR0-7 + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + return (ne2000->mchash[address - 8]); + break; + } + + return (0); + break; + + case 0x02: + pclog("page 2 read from port %04x\n", address); + + switch (address) { + case 0x1: // PSTART + return (ne2000->page_start); + break; + + case 0x2: // PSTOP + return (ne2000->page_stop); + break; + + case 0x3: // Remote Next-packet pointer + return (ne2000->rempkt_ptr); + break; + + case 0x4: // TPSR + return (ne2000->tx_page_start); + break; + + case 0x5: // Local Next-packet pointer + return (ne2000->localpkt_ptr); + break; + + case 0x6: // Address counter (upper) + return (ne2000->address_cnt >> 8); + break; + + case 0x7: // Address counter (lower) + return (ne2000->address_cnt & 0xff); + break; + + case 0x8: // Reserved + case 0x9: + case 0xa: + case 0xb: + pclog("reserved read - page 2, 0x%02x\n", address); + break; + + case 0xc: // RCR + return ((ne2000->RCR.monitor << 5) | + (ne2000->RCR.promisc << 4) | + (ne2000->RCR.multicast << 3) | + (ne2000->RCR.broadcast << 2) | + (ne2000->RCR.runts_ok << 1) | + (ne2000->RCR.errors_ok)); + break; + + case 0xd: // TCR + return ((ne2000->TCR.coll_prio << 4) | + (ne2000->TCR.ext_stoptx << 3) | + ((ne2000->TCR.loop_cntl & 0x3) << 1) | + (ne2000->TCR.crc_disable)); + break; + + case 0xe: // DCR + return (((ne2000->DCR.fifo_size & 0x3) << 5) | + (ne2000->DCR.auto_rx << 4) | + (ne2000->DCR.loop << 3) | + (ne2000->DCR.longaddr << 2) | + (ne2000->DCR.endian << 1) | + (ne2000->DCR.wdsize)); + break; + + case 0xf: // IMR + return ((ne2000->IMR.rdma_inte << 6) | + (ne2000->IMR.cofl_inte << 5) | + (ne2000->IMR.overw_inte << 4) | + (ne2000->IMR.txerr_inte << 3) | + (ne2000->IMR.rxerr_inte << 2) | + (ne2000->IMR.tx_inte << 1) | + (ne2000->IMR.rx_inte)); + break; + } + break; + + case 3: + if (network_card_current == 1) fatal("ne2000 unknown value of pgsel in read - %d\n", ne2000->CR.pgsel); + + switch(address) + { + case 0: + return ne2000->cr; + case 1: + return ne2000->i9346cr; + case 3: + return ne2000->config0; + case 5: + return ne2000->config2; + case 6: + return ne2000->config3; + case 9: + return 0xFF; + case 0xE: + return ne2000->i8029asid0; + case 0xF: + return ne2000->i8029asid1; + } + break; + + default: + fatal("ne2000 unknown value of pgsel in read - %d\n", ne2000->CR.pgsel); + } + } + return ret; +} + +// +// write_handler/write - i/o 'catcher' function called from BOCHS +// mainline when the CPU attempts a write in the i/o space registered +// by this ne2000 instance +// +void ne2000_write(uint32_t address, uint16_t value, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("write address %x, val=%x\n", address, value); + + address &= 0xf; + + // + // The high 16 bytes of i/o space are for the ne2000 asic - + // the low 16 bytes are for the DS8390, with the current + // page being selected by the PS0,PS1 registers in the + // command register + // + if (address == 0x00) { + pclog("wrote 0x%02x to CR\n", value); + + // Validate remote-DMA + if ((value & 0x38) == 0x00) { + pclog("CR write - invalid rDMA value 0\n"); + value |= 0x20; /* dma_cmd == 4 is a safe default */ + //value = 0x22; /* dma_cmd == 4 is a safe default */ + } + + // Check for s/w reset + if (value & 0x01) { + ne2000->ISR.reset = 1; + ne2000->CR.stop = 1; + } else { + ne2000->CR.stop = 0; + } + + ne2000->CR.rdma_cmd = (value & 0x38) >> 3; + + // If start command issued, the RST bit in the ISR + // must be cleared + if ((value & 0x02) && !ne2000->CR.start) { + ne2000->ISR.reset = 0; + } + + ne2000->CR.start = ((value & 0x02) == 0x02); + ne2000->CR.pgsel = (value & 0xc0) >> 6; + + // Check for send-packet command + if (ne2000->CR.rdma_cmd == 3) { + // Set up DMA read from receive ring + ne2000->remote_start = ne2000->remote_dma = + ne2000->bound_ptr * 256; + ne2000->remote_bytes = *((uint16_t*) & + ne2000->mem[ne2000->bound_ptr * 256 + 2 - BX_NE2K_MEMSTART]); + pclog("Sending buffer #x%x length %d\n", + ne2000->remote_start, + ne2000->remote_bytes); + } + + // Check for start-tx + if ((value & 0x04) && ne2000->TCR.loop_cntl) { + // loopback mode + if (ne2000->TCR.loop_cntl != 1) { + pclog("Loop mode %d not supported.\n", ne2000->TCR.loop_cntl); + } else { + ne2000_rx_frame (ne2000, &ne2000->mem[ne2000->tx_page_start*256 - + BX_NE2K_MEMSTART], + ne2000->tx_bytes); + + // do a TX interrupt + // Generate an interrupt if not masked and not one in progress + if (ne2000->IMR.tx_inte && !ne2000->ISR.pkt_tx) { + //LOG_MSG("tx complete interrupt"); + picint(1 << ne2000->base_irq); + } + ne2000->ISR.pkt_tx = 1; + } + } else if (value & 0x04) { + // start-tx and no loopback + if (ne2000->CR.stop || !ne2000->CR.start) + pclog("CR write - tx start, dev in reset\n"); + + if (ne2000->tx_bytes == 0) + pclog("CR write - tx start, tx bytes == 0\n"); + + // Send the packet to the system driver + /* TODO: Transmit packet */ + //BX_NE2K_THIS ethdev->sendpkt(& ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); + //pcap_sendpacket(adhandle,&ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); +if(net_is_slirp) { + slirp_input(&ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); + pclog("ne2000 slirp sending packet\n"); + } +if(net_is_pcap && net_pcap!=NULL) { + _pcap_sendpacket(net_pcap, &ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); + pclog("ne2000 pcap sending packet\n"); + } + + ne2000_tx_event(value, ne2000); + // Schedule a timer to trigger a tx-complete interrupt + // The number of microseconds is the bit-time / 10. + // The bit-time is the preamble+sfd (64 bits), the + // inter-frame gap (96 bits), the CRC (4 bytes), and the + // the number of bits in the frame (s.tx_bytes * 8). + // + + /* TODO: Code transmit timer */ + /* + bx_pc_system.activate_timer(ne2000->tx_timer_index, + (64 + 96 + 4*8 + ne2000->tx_bytes*8)/10, + 0); // not continuous + */ + } // end transmit-start branch + + // Linux probes for an interrupt by setting up a remote-DMA read + // of 0 bytes with remote-DMA completion interrupts enabled. + // Detect this here + if (ne2000->CR.rdma_cmd == 0x01 && + ne2000->CR.start && + ne2000->remote_bytes == 0) { + ne2000->ISR.rdma_done = 1; + if (ne2000->IMR.rdma_inte) { + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } + } + } else { + switch (ne2000->CR.pgsel) { + case 0x00: + pclog("page 0 write to port %04x\n", address); + + // It appears to be a common practice to use outw on page0 regs... + + switch (address) { + case 0x1: // PSTART + ne2000->page_start = value; + break; + + case 0x2: // PSTOP + // BX_INFO(("Writing to PSTOP: %02x", value)); + ne2000->page_stop = value; + break; + + case 0x3: // BNRY + ne2000->bound_ptr = value; + break; + + case 0x4: // TPSR + ne2000->tx_page_start = value; + break; + + case 0x5: // TBCR0 + // Clear out low byte and re-insert + ne2000->tx_bytes &= 0xff00; + ne2000->tx_bytes |= (value & 0xff); + break; + + case 0x6: // TBCR1 + // Clear out high byte and re-insert + ne2000->tx_bytes &= 0x00ff; + ne2000->tx_bytes |= ((value & 0xff) << 8); + break; + + case 0x7: // ISR + value &= 0x7f; // clear RST bit - status-only bit + // All other values are cleared iff the ISR bit is 1 + ne2000->ISR.pkt_rx &= ~((int)((value & 0x01) == 0x01)); + ne2000->ISR.pkt_tx &= ~((int)((value & 0x02) == 0x02)); + ne2000->ISR.rx_err &= ~((int)((value & 0x04) == 0x04)); + ne2000->ISR.tx_err &= ~((int)((value & 0x08) == 0x08)); + ne2000->ISR.overwrite &= ~((int)((value & 0x10) == 0x10)); + ne2000->ISR.cnt_oflow &= ~((int)((value & 0x20) == 0x20)); + ne2000->ISR.rdma_done &= ~((int)((value & 0x40) == 0x40)); + value = ((ne2000->ISR.rdma_done << 6) | + (ne2000->ISR.cnt_oflow << 5) | + (ne2000->ISR.overwrite << 4) | + (ne2000->ISR.tx_err << 3) | + (ne2000->ISR.rx_err << 2) | + (ne2000->ISR.pkt_tx << 1) | + (ne2000->ISR.pkt_rx)); + value &= ((ne2000->IMR.rdma_inte << 6) | + (ne2000->IMR.cofl_inte << 5) | + (ne2000->IMR.overw_inte << 4) | + (ne2000->IMR.txerr_inte << 3) | + (ne2000->IMR.rxerr_inte << 2) | + (ne2000->IMR.tx_inte << 1) | + (ne2000->IMR.rx_inte)); + if (value == 0) + picintc(1 << ne2000->base_irq); + //DEV_pic_lower_irq(ne2000->base_irq); + break; + + case 0x8: // RSAR0 + // Clear out low byte and re-insert + ne2000->remote_start &= 0xff00; + ne2000->remote_start |= (value & 0xff); + ne2000->remote_dma = ne2000->remote_start; + break; + + case 0x9: // RSAR1 + // Clear out high byte and re-insert + ne2000->remote_start &= 0x00ff; + ne2000->remote_start |= ((value & 0xff) << 8); + ne2000->remote_dma = ne2000->remote_start; + break; + + case 0xa: // RBCR0 + // Clear out low byte and re-insert + ne2000->remote_bytes &= 0xff00; + ne2000->remote_bytes |= (value & 0xff); + break; + + case 0xb: // RBCR1 + // Clear out high byte and re-insert + ne2000->remote_bytes &= 0x00ff; + ne2000->remote_bytes |= ((value & 0xff) << 8); + break; + + case 0xc: // RCR + // Check if the reserved bits are set + if (value & 0xc0) + pclog("RCR write, reserved bits set\n"); + + // Set all other bit-fields + ne2000->RCR.errors_ok = ((value & 0x01) == 0x01); + ne2000->RCR.runts_ok = ((value & 0x02) == 0x02); + ne2000->RCR.broadcast = ((value & 0x04) == 0x04); + ne2000->RCR.multicast = ((value & 0x08) == 0x08); + ne2000->RCR.promisc = ((value & 0x10) == 0x10); + ne2000->RCR.monitor = ((value & 0x20) == 0x20); + + // Monitor bit is a little suspicious... + if (value & 0x20) + pclog("RCR write, monitor bit set!\n"); + break; + + case 0xd: // TCR + // Check reserved bits + if (value & 0xe0) + pclog("TCR write, reserved bits set\n"); + + // Test loop mode (not supported) + if (value & 0x06) { + ne2000->TCR.loop_cntl = (value & 0x6) >> 1; + pclog("TCR write, loop mode %d not supported\n", ne2000->TCR.loop_cntl); + } else { + ne2000->TCR.loop_cntl = 0; + } + + // Inhibit-CRC not supported. + if (value & 0x01) + { + //fatal("ne2000 TCR write, inhibit-CRC not supported\n"); + pclog("ne2000 TCR write, inhibit-CRC not supported\n"); + return; + } + + // Auto-transmit disable very suspicious + if (value & 0x08) { + //fatal("ne2000 TCR write, auto transmit disable not supported\n"); + pclog("ne2000 TCR write, auto transmit disable not supported\n"); + } + + // Allow collision-offset to be set, although not used + ne2000->TCR.coll_prio = ((value & 0x08) == 0x08); + break; + + case 0xe: // DCR + // the loopback mode is not suppported yet + if (!(value & 0x08)) { + pclog("DCR write, loopback mode selected\n"); + } + // It is questionable to set longaddr and auto_rx, since they + // aren't supported on the ne2000. Print a warning and continue + if (value & 0x04) + pclog("DCR write - LAS set ???\n"); + if (value & 0x10) + pclog("DCR write - AR set ???\n"); + + // Set other values. + ne2000->DCR.wdsize = ((value & 0x01) == 0x01); + ne2000->DCR.endian = ((value & 0x02) == 0x02); + ne2000->DCR.longaddr = ((value & 0x04) == 0x04); // illegal ? + ne2000->DCR.loop = ((value & 0x08) == 0x08); + ne2000->DCR.auto_rx = ((value & 0x10) == 0x10); // also illegal ? + ne2000->DCR.fifo_size = (value & 0x50) >> 5; + break; + + case 0xf: // IMR + // Check for reserved bit + if (value & 0x80) + pclog("IMR write, reserved bit set\n"); + + // Set other values + ne2000->IMR.rx_inte = ((value & 0x01) == 0x01); + ne2000->IMR.tx_inte = ((value & 0x02) == 0x02); + ne2000->IMR.rxerr_inte = ((value & 0x04) == 0x04); + ne2000->IMR.txerr_inte = ((value & 0x08) == 0x08); + ne2000->IMR.overw_inte = ((value & 0x10) == 0x10); + ne2000->IMR.cofl_inte = ((value & 0x20) == 0x20); + ne2000->IMR.rdma_inte = ((value & 0x40) == 0x40); + if(ne2000->ISR.pkt_tx && ne2000->IMR.tx_inte) { + pclog("tx irq retrigger\n"); + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + } + break; + } + break; + + case 0x01: + pclog("page 1 w offset %04x\n", address); + switch (address) { + case 0x1: // PAR0-5 + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + ne2000->physaddr[address - 1] = value; + break; + + case 0x7: // CURR + ne2000->curr_page = value; + break; + + case 0x8: // MAR0-7 + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + ne2000->mchash[address - 8] = value; + break; + } + break; + + case 0x02: + if (address != 0) + pclog("page 2 write ?\n"); + + switch (address) { + case 0x1: // CLDA0 + // Clear out low byte and re-insert + ne2000->local_dma &= 0xff00; + ne2000->local_dma |= (value & 0xff); + break; + + case 0x2: // CLDA1 + // Clear out high byte and re-insert + ne2000->local_dma &= 0x00ff; + ne2000->local_dma |= ((value & 0xff) << 8); + break; + + case 0x3: // Remote Next-pkt pointer + ne2000->rempkt_ptr = value; + break; + + case 0x4: + //fatal("page 2 write to reserved offset 4\n"); + //OS/2 Warp can cause this to freak out. + pclog("ne2000 page 2 write to reserved offset 4\n"); + break; + + case 0x5: // Local Next-packet pointer + ne2000->localpkt_ptr = value; + break; + + case 0x6: // Address counter (upper) + // Clear out high byte and re-insert + ne2000->address_cnt &= 0x00ff; + ne2000->address_cnt |= ((value & 0xff) << 8); + break; + + case 0x7: // Address counter (lower) + // Clear out low byte and re-insert + ne2000->address_cnt &= 0xff00; + ne2000->address_cnt |= (value & 0xff); + break; + + case 0x8: + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + //fatal("page 2 write to reserved offset %0x\n", address); + pclog("ne2000 page 2 write to reserved offset %0x\n", address); + default: + break; + } + break; + + case 3: + if (network_card_current == 1) + { + pclog("ne2000 unknown value of pgsel in write - %d\n", ne2000->CR.pgsel); + break; + } + + switch (address) + { + case 0: + ne2000->cr = value; + break; + case 1: + ne2000->i9346cr = value; + break; + case 5: + if ((ne2000->i9346cr & 0xC0) == 0xC0) ne2000->config2 = value; + break; + case 6: + if ((ne2000->i9346cr & 0xC0) == 0xC0) ne2000->config3 = value; + break; + case 9: + ne2000->hltclk = value; + break; + } + break; + + default: + //fatal("ne2K: unknown value of pgsel in write - %d\n", ne2000->CR.pgsel); + pclog("ne2000 unknown value of pgsel in write - %d\n", ne2000->CR.pgsel); + break; + } + } +} + +/* + * mcast_index() - return the 6-bit index into the multicast + * table. Stolen unashamedly from FreeBSD's if_ed.c + */ +static int mcast_index(const void *dst) +{ +#define POLYNOMIAL 0x04c11db6 + unsigned long crc = 0xffffffffL; + int carry, i, j; + unsigned char b; + unsigned char *ep = (unsigned char *) dst; + + for (i = 6; --i >= 0;) { + b = *ep++; + for (j = 8; --j >= 0;) { + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); + crc <<= 1; + b >>= 1; + if (carry) + crc = ((crc ^ POLYNOMIAL) | carry); + } + } + return (crc >> 26); +#undef POLYNOMIAL +} + +/* + * rx_frame() - called by the platform-specific code when an + * ethernet frame has been received. The destination address + * is tested to see if it should be accepted, and if the + * rx ring has enough room, it is copied into it and + * the receive process is updated + */ +void ne2000_rx_frame(void *p, const void *buf, int io_len) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + int pages; + int avail; + int idx; + int wrapped; + int nextpage; + uint8_t pkthdr[4]; + uint8_t *pktbuf = (uint8_t *) buf; + uint8_t *startptr; + static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; + + if(io_len != 60) { + pclog("rx_frame with length %d\n", io_len); + } + + //LOG_MSG("stop=%d, pagestart=%x, dcr_loop=%x, tcr_loopcntl=%x", + // ne2000->CR.stop, ne2000->page_start, + // ne2000->DCR.loop, ne2000->TCR.loop_cntl); + if ((ne2000->CR.stop != 0) || + (ne2000->page_start == 0) /*|| + ((ne2000->DCR.loop == 0) && + (ne2000->TCR.loop_cntl != 0))*/) { + return; + } + + // Add the pkt header + CRC to the length, and work + // out how many 256-byte pages the frame would occupy + pages = (io_len + 4 + 4 + 255)/256; + + if (ne2000->curr_page < ne2000->bound_ptr) { + avail = ne2000->bound_ptr - ne2000->curr_page; + } else { + avail = (ne2000->page_stop - ne2000->page_start) - + (ne2000->curr_page - ne2000->bound_ptr); + wrapped = 1; + } + + // Avoid getting into a buffer overflow condition by not attempting + // to do partial receives. The emulation to handle this condition + // seems particularly painful. + if ((avail < pages) +#if BX_NE2K_NEVER_FULL_RING + || (avail == pages) +#endif + ) { + pclog("no space\n"); + return; + } + + if ((io_len < 40/*60*/) && !ne2000->RCR.runts_ok) { + pclog("rejected small packet, length %d\n", io_len); + return; + } + // some computers don't care... + if (io_len < 60) io_len=60; + + // Do address filtering if not in promiscuous mode + if (! ne2000->RCR.promisc) { + if (!memcmp(buf, bcast_addr, 6)) { + if (!ne2000->RCR.broadcast) { + return; + } + } else if (pktbuf[0] & 0x01) { + if (! ne2000->RCR.multicast) { + return; + } + idx = mcast_index(buf); + if (!(ne2000->mchash[idx >> 3] & (1 << (idx & 0x7)))) { + return; + } + } else if (0 != memcmp(buf, ne2000->physaddr, 6)) { + return; + } + } else { + pclog("rx_frame promiscuous receive\n"); + } + + pclog("rx_frame %d to %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x\n", + io_len, + pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3], pktbuf[4], pktbuf[5], + pktbuf[6], pktbuf[7], pktbuf[8], pktbuf[9], pktbuf[10], pktbuf[11]); + + nextpage = ne2000->curr_page + pages; + if (nextpage >= ne2000->page_stop) { + nextpage -= ne2000->page_stop - ne2000->page_start; + } + + // Setup packet header + pkthdr[0] = 0; // rx status - old behavior + pkthdr[0] = 1; // Probably better to set it all the time + // rather than set it to 0, which is clearly wrong. + if (pktbuf[0] & 0x01) { + pkthdr[0] |= 0x20; // rx status += multicast packet + } + pkthdr[1] = nextpage; // ptr to next packet + pkthdr[2] = (io_len + 4) & 0xff; // length-low + pkthdr[3] = (io_len + 4) >> 8; // length-hi + + // copy into buffer, update curpage, and signal interrupt if config'd + startptr = & ne2000->mem[ne2000->curr_page * 256 - + BX_NE2K_MEMSTART]; + if ((nextpage > ne2000->curr_page) || + ((ne2000->curr_page + pages) == ne2000->page_stop)) { + memcpy(startptr, pkthdr, 4); + memcpy(startptr + 4, buf, io_len); + ne2000->curr_page = nextpage; + } else { + int endbytes = (ne2000->page_stop - ne2000->curr_page) + * 256; + memcpy(startptr, pkthdr, 4); + memcpy(startptr + 4, buf, endbytes - 4); + startptr = & ne2000->mem[ne2000->page_start * 256 - + BX_NE2K_MEMSTART]; + memcpy(startptr, (void *)(pktbuf + endbytes - 4), + io_len - endbytes + 8); + ne2000->curr_page = nextpage; + } + + ne2000->RSR.rx_ok = 1; + if (pktbuf[0] & 0x80) { + ne2000->RSR.rx_mbit = 1; + } + + ne2000->ISR.pkt_rx = 1; + + if (ne2000->IMR.rx_inte) { + //LOG_MSG("packet rx interrupt"); + picint(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } //else LOG_MSG("no packet rx interrupt"); + +} + +void ne2000_tx_timer(void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("tx_timer\n"); + ne2000->TSR.tx_ok = 1; + // Generate an interrupt if not masked and not one in progress + if (ne2000->IMR.tx_inte && !ne2000->ISR.pkt_tx) { + //LOG_MSG("tx complete interrupt"); + picint(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } //else LOG_MSG("no tx complete interrupt"); + ne2000->ISR.pkt_tx = 1; + ne2000->tx_timer_active = 0; +} + +static void ne2000_tx_event(int val, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + ne2000_tx_timer(ne2000); +} + +static void ne2000_poller(void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + struct queuepacket *qp; + const unsigned char *data; + struct pcap_pkthdr h; + + + int res; +if(net_is_slirp) { + while(QueuePeek(slirpq)>0) + { + qp=QueueDelete(slirpq); + if((ne2000->DCR.loop == 0) || (ne2000->TCR.loop_cntl != 0)) + { + free(qp); + return; + } + ne2000_rx_frame(ne2000,&qp->data,qp->len); + pclog("ne2000 inQ:%d got a %dbyte packet @%d\n",QueuePeek(slirpq),qp->len,qp); + free(qp); + } + fizz++; + if(fizz>1200){fizz=0;slirp_tic();} + }//end slirp +if(net_is_pcap && net_pcap!=NULL) + { + data=_pcap_next(net_pcap,&h); + if(data==0x0){goto WTF;} + if((memcmp(data+6,maclocal,6))==0) + pclog("ne2000 we just saw ourselves\n"); + else { + if((ne2000->DCR.loop == 0) || (ne2000->TCR.loop_cntl != 0)) + { + return; + } + pclog("ne2000 pcap received a frame %d bytes\n",h.caplen); + ne2000_rx_frame(ne2000,data,h.caplen); + } + WTF: + {} + } +} + + +uint16_t io_base = 0x300; + +uint8_t ne2000_pci_regs[256]; + +void ne2000_io_set(uint16_t addr, ne2000_t *ne2000) +{ + io_sethandler(addr, 0x0010, ne2000_read, NULL, NULL, ne2000_write, NULL, NULL, ne2000); + io_sethandler(addr+0x10, 0x0010, ne2000_asic_read_b, ne2000_asic_read_w, NULL, ne2000_asic_write_b, ne2000_asic_write_w, NULL, ne2000); + io_sethandler(addr+0x1f, 0x0001, ne2000_reset_read, NULL, NULL, ne2000_reset_write, NULL, NULL, ne2000); +} + +void ne2000_io_remove(uint16_t addr, ne2000_t *ne2000) +{ + io_removehandler(addr, 0x0010, ne2000_read, NULL, NULL, ne2000_write, NULL, NULL, ne2000); + io_removehandler(addr+0x10, 0x0010, ne2000_asic_read_b, ne2000_asic_read_w, NULL, ne2000_asic_write_b, ne2000_asic_write_w, NULL, ne2000); + io_removehandler(addr+0x1f, 0x0001, ne2000_reset_read, NULL, NULL, ne2000_reset_write, NULL, NULL, ne2000); +} + +uint8_t ne2000_pci_read(int func, int addr, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *) p; + + // pclog("NE2000 PCI read %08X\n", addr); + switch (addr) + { + case 0x00:/* case 0x2C:*/ return 0xec; + case 0x01:/* case 0x2D:*/ return 0x10; + + case 0x02:/* case 0x2E:*/ return 0x29; + case 0x03:/* case 0x2F:*/ return 0x80; + + case 0x2C: return 0xF4; + case 0x2D: return 0x1A; + case 0x2E: return 0x00; + case 0x2F: return 0x11; + + case 0x04: + return ne2000_pci_regs[0x04] & 3; /*Respond to IO and memory accesses*/ + case 0x05: + return ne2000_pci_regs[0x05]; + + case 0x07: return 2; + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0B: return ne2000_pci_regs[0x0B]; + + case 0x10: return 1; /*I/O space*/ + case 0x11: return ne2000_pci_regs[0x11]; + case 0x12: return ne2000_pci_regs[0x12]; + case 0x13: return ne2000_pci_regs[0x13]; + + case 0x30: return ne2000_pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return (ne2000_pci_regs[0x31] & 0xE0) | 0x18; + case 0x32: return ne2000_pci_regs[0x32]; + case 0x33: return ne2000_pci_regs[0x33]; + + case 0x3C: return ne2000_pci_regs[0x3C]; + case 0x3D: return ne2000_pci_regs[0x3D]; + + default: return 0; + } + return 0; +} + +int bios_addr = 0xD0000; + +void ne2000_update_bios(ne2000_t *ne2000) +{ + int reg_bios_enable; + FILE *f; + int filelen; + struct stat st; + + // reg_bios_enable = ne2000_pci_regs[0x30]; + reg_bios_enable = 1; + + /* PCI BIOS stuff, just enable_disable. */ + if (!disable_netbios && reg_bios_enable) + { + mem_mapping_enable(&ne2000->bios_rom.mapping); + mem_mapping_set_addr(&ne2000->bios_rom.mapping, bios_addr, 0x8000); + pclog("Network BIOS now at: %08X\n", bios_addr); + // if (network_card_current == 2) *(uint32_t *) &(ne2000_pci_regs[0x30]) = bios_addr | 0x1801; + } + else + { + mem_mapping_disable(&ne2000->bios_rom.mapping); + if (network_card_current == 2) *(uint32_t *) &(ne2000_pci_regs[0x30]) = 0; + } +} + +void ne2000_pci_write(int func, int addr, uint8_t val, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *) p; + + uint32_t ba1, ba2, ba3, ba4; + + // pclog("ne2000_pci_write: addr=%02x val=%02x\n", addr, val); + switch (addr) + { + case 0x04: + ne2000_pci_regs[0x04] = val & 3; + if (val & PCI_COMMAND_IO) + { + if (io_base >= 0x280) + { + ne2000_io_set(io_base, ne2000); + ne2000_reset(BX_RESET_SOFTWARE, ne2000); + } + } + else + if (io_base >= 0x280) ne2000_io_remove(io_base, ne2000); + break; + + case 0x10: + val &= 0xfc; + val |= 1; + case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O, if old base was >= 0x280. */ + if (io_base < 0x280) ne2000_io_remove(io_base, ne2000); + /* Then let's set the PCI regs. */ + ne2000_pci_regs[addr] = val; + /* Then let's calculate the new I/O base. */ + // io_base = (uint16_t) ((*(uint32_t *) (&ne2000_pci_regs[0x10])) & 0xff00); + io_base = (*(uint32_t *) (&ne2000_pci_regs[0x10])) & 0xff00; + /* If the base is below 0x280, return. */ + if (io_base < 0x280) return; + /* Set new I/O base. */ + ne2000_io_set(io_base, ne2000); + /* Log the new base. */ + // pclog("NE2000 RTL8029AS PCI: New I/O base is %04X\n" , io_base); + /* We're done, so get out of the here. */ + return; + + case 0x30: case 0x31: case 0x32: case 0x33: + ne2000_pci_regs[addr] = val/* | ((addr == 0x30) ? 1 : 0)*/; + bios_addr = (*(uint32_t *) (&ne2000_pci_regs[0x30])) & 0x000f8000; + (*(uint32_t *) (&ne2000_pci_regs[0x30])) &= 0x000f8000; + (*(uint32_t *) (&ne2000_pci_regs[0x30])) |= 0x1801; + // bios_addr = ((ne2000_pci_regs[0x31] & 0x00) << 8) | (ne2000_pci_regs[0x32] << 16) | (ne2000_pci_regs[0x33] << 24); + ne2000_update_bios(ne2000); + return; + + case 0x3C: + ne2000_pci_regs[addr] = val; + if (val != 0xFF) + { + pclog("NE2000 IRQ now: %i\n", val); + ne2000_setirq(ne2000, val); + ne2000_reset(BX_RESET_SOFTWARE, ne2000); + } + return; + } +} + +void rtl8029as_init(ne2000_t *ne2000) +{ + pci_add(ne2000_pci_read, ne2000_pci_write, ne2000); + + memset(ne2000_pci_regs, 0, 256); + + ne2000_pci_regs[0x04] = 3; + ne2000_pci_regs[0x05] = 0; + + ne2000_pci_regs[0x07] = 2; + + /* Network controller. */ + ne2000_pci_regs[0x0B] = 2; + + *(uint32_t *) &(ne2000_pci_regs[0x10]) = 0x0000FF01; + ne2000_io_set(io_base, ne2000); + + *(uint32_t *) &(ne2000_pci_regs[0x30]) = 0x000F8000 | 0x1801; + bios_addr = 0xD0000; + + if (disable_netbios) ne2000_pci_regs[0x33] = 0x00; + + ne2000_pci_regs[0x3C] = 10; + ne2000_pci_regs[0x3D] = 1; + + memset(rtl8029as_eeprom, 0, 128); + rtl8029as_eeprom[0x76] = rtl8029as_eeprom[0x7A] = rtl8029as_eeprom[0x7E] = 0x29; + rtl8029as_eeprom[0x77] = rtl8029as_eeprom[0x7B] = rtl8029as_eeprom[0x7F] = 0x80; + rtl8029as_eeprom[0x78] = rtl8029as_eeprom[0x7C] = 0x10; + rtl8029as_eeprom[0x79] = rtl8029as_eeprom[0x7D] = 0xEC; + + ne2000->i8029id0 = 0x50; + ne2000->i8029id1 = 0x43; + + ne2000->cr = 0x21; + ne2000->i9346cr = 0; + ne2000->config0 = 0; + ne2000->config2 = 3; + ne2000->config3 = 0; + ne2000->hltclk = 0x52; + ne2000->i8029asid0 = 0x29; + ne2000->i8029asid1 = 0x80; +} + +void *ne2000_init() +{ + struct in_addr myaddr; + int rc; + int config_net_type; + int net_type; + + ne2000_t *ne2000 = malloc(sizeof(ne2000_t)); + memset(ne2000, 0, sizeof(ne2000_t)); + + uint16_t addr = 0xC000; + if (network_card_current == 1) addr = device_get_config_int("addr"); + disable_netbios = device_get_config_int("disable_netbios"); + io_base = addr; + if (network_card_current == 1) ne2000_setirq(ne2000, device_get_config_int("irq")); + + //net_type + //0 pcap + //1 slirp + // + config_net_type = device_get_config_int("net_type"); + // net_is_slirp = config_get_int(NULL, "net_type", 1); + /* Network type is now specified in device config. */ + net_is_slirp = config_net_type ? 1 : 0; + // pclog("ne2000 pcap device %s\n",config_get_string(NULL,"pcap_device","nothing")); + + //Check that we have a string setup, otherwise turn pcap off + if(!strcmp("nothing",config_get_string(NULL,"pcap_device","nothing"))) { + net_is_pcap = 0; + } + else { + if( net_is_slirp == 0) + net_is_pcap = 1; + } + + ne2000_io_set(addr, ne2000); + memcpy(ne2000->physaddr, maclocal, 6); + + if (!disable_netbios) + { + if (network_card_current == 2) + { + rtl8029as_init(ne2000); + rom_init(&ne2000->bios_rom, "roms/rtl8029as.rom", 0xd0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (PCI) + mem_mapping_disable(&ne2000->bios_rom.mapping); + } + else + { + rom_init(&ne2000->bios_rom, "roms/ne2000.rom", 0xd0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + } + } + + ne2000_reset(BX_RESET_HARDWARE, ne2000); + vlan_handler(ne2000_poller, ne2000); + + pclog("ne2000 init 0x%X %d\tslirp is %d net_is_pcap is %d\n",addr,device_get_config_int("irq"),net_is_slirp,net_is_pcap); + + //need a switch statment for more network types. + + if ( net_is_slirp ) { + pclog("ne2000 initalizing SLiRP\n"); + net_is_pcap=0; + rc=slirp_init(); + pclog("ne2000 slirp_init returned: %d\n",rc); + if ( rc == 0 ) + { + pclog("ne2000 slirp initalized!\n"); + inet_aton("10.0.2.15",&myaddr); + //YES THIS NEEDS TO PULL FROM A CONFIG FILE... but for now. + rc=slirp_redir(0,42323,myaddr,23); + pclog("ne2000 slirp redir returned %d on port 42323 -> 23\n",rc); + rc=slirp_redir(0,42380,myaddr,80); + pclog("ne2000 slirp redir returned %d on port 42380 -> 80\n",rc); + rc=slirp_redir(0,42443,myaddr,443); + pclog("ne2000 slirp redir returned %d on port 42443 -> 443\n",rc); + rc=slirp_redir(0,42322,myaddr,22); + pclog("ne2000 slirp redir returned %d on port 42322 -> 22\n",rc); + + //Kali + rc=slirp_redir(1,2213,myaddr,2213); + pclog("ne2000 slirp redir returned %d on port 2213 -> 2213\n",rc); + rc=slirp_redir(1,2231,myaddr,2231); + pclog("ne2000 slirp redir returned %d on port 2231 -> 2231\n",rc); + rc=slirp_redir(1,2271,myaddr,2271); + pclog("ne2000 slirp redir returned %d on port 2271 -> 2271\n",rc); + + + net_slirp_inited=1; + slirpq = QueueCreate(); + net_is_slirp=1; + fizz=0; + pclog("ne2000 slirpq is %x\n",&slirpq); + } + else { + net_slirp_inited=0; + net_is_slirp=0; + } + } + if ( net_is_pcap ) { //pcap + char errbuf[32768]; + + pclog("ne2000 initalizing libpcap\n"); + net_is_slirp=0; + net_hLib = LoadLibraryA(net_lib_name); + if(net_hLib==0) + { + pclog("ne2000 Failed to load %s\n",net_lib_name); + net_is_pcap=0; + //return; + } + _pcap_lib_version =(PCAP_LIB_VERSION)GetProcAddress(net_hLib,"pcap_lib_version"); + _pcap_open_live=(PCAP_OPEN_LIVE)GetProcAddress(net_hLib,"pcap_open_live"); + _pcap_sendpacket=(PCAP_SENDPACKET)GetProcAddress(net_hLib,"pcap_sendpacket"); + _pcap_setnonblock=(PCAP_SETNONBLOCK)GetProcAddress(net_hLib,"pcap_setnonblock"); + _pcap_next=(PCAP_NEXT)GetProcAddress(net_hLib,"pcap_next"); + _pcap_close=(PCAP_CLOSE)GetProcAddress(net_hLib,"pcap_close"); + _pcap_getnonblock=(PCAP_GETNONBLOCK)GetProcAddress(net_hLib,"pcap_getnonblock"); + _pcap_compile=(PCAP_COMPILE)GetProcAddress(net_hLib,"pcap_compile"); + _pcap_setfilter=(PCAP_SETFILTER)GetProcAddress(net_hLib,"pcap_setfilter"); + + if(_pcap_lib_version && _pcap_open_live && _pcap_sendpacket && _pcap_setnonblock && _pcap_next && _pcap_close && _pcap_getnonblock) + { + pclog("ne2000 Pcap version [%s]\n",_pcap_lib_version()); + + //if((net_pcap=_pcap_open_live("\\Device\\NPF_{0CFA803F-F443-4BB9-A83A-657029A98195}",1518,1,15,errbuf))==0) + if((net_pcap=_pcap_open_live(config_get_string(NULL,"pcap_device","nothing"),1518,1,15,errbuf))==0) + { + pclog("ne2000 pcap_open_live error on %s!\n",config_get_string(NULL,"pcap_device","whatever the ethernet is")); + net_is_pcap=0; return(ne2000); //YUCK!!! + } + } + else { + pclog("%d %d %d %d %d %d %d\n",_pcap_lib_version, _pcap_open_live,_pcap_sendpacket,_pcap_setnonblock,_pcap_next,_pcap_close,_pcap_getnonblock); + net_is_pcap=1; + } + + //Time to check that we are in non-blocking mode. + rc=_pcap_getnonblock(net_pcap,errbuf); + pclog("ne2000 pcap is currently in %s mode\n",rc? "non-blocking":"blocking"); + switch(rc) + { + case 0: + pclog("ne2000 Setting interface to non-blocking mode.."); + rc=_pcap_setnonblock(net_pcap,1,errbuf); + if(rc==0) { //no errors! + pclog(".."); + rc=_pcap_getnonblock(net_pcap,errbuf); + if(rc==1) { + pclog("..!",rc); + net_is_pcap=1; + } + else{ + pclog("\tunable to set pcap into non-blocking mode!\nContinuining without pcap.\n"); + net_is_pcap=0; + } + }//end set nonblock + else{pclog("There was an unexpected error of [%s]\n\nexiting.\n",errbuf);net_is_pcap=0;} + pclog("\n"); + break; + case 1: + pclog("non blocking\n"); + break; + default: + pclog("this isn't right!!!\n"); + net_is_pcap=0; + break; + } + if( net_is_pcap ) { + if(_pcap_compile && _pcap_setfilter) { //we can do this! + struct bpf_program fp; + char filter_exp[255]; + pclog("ne2000 Building packet filter..."); + sprintf(filter_exp,"( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", \ + maclocal[0], maclocal[1], maclocal[2], maclocal[3], maclocal[4], maclocal[5],\ + maclocal[0], maclocal[1], maclocal[2], maclocal[3], maclocal[4], maclocal[5]); + + //I'm doing a MAC level filter so TCP/IP doesn't matter. + if (_pcap_compile(net_pcap, &fp, filter_exp, 0, 0xffffffff) == -1) { + pclog("\nne2000 Couldn't compile filter\n"); + } + else { + pclog("..."); + if (_pcap_setfilter(net_pcap, &fp) == -1) { + pclog("\nError installing pcap filter.\n"); + }//end of set_filter failure + else { + pclog("...!\n"); + } + } + pclog("ne2000 Using filter\t[%s]\n",filter_exp); + //scanf(filter_exp); //pause + } + else + { + pclog("ne2000 Your platform lacks pcap_compile & pcap_setfilter\n"); + net_is_pcap=0; + } + pclog("ne2000 net_is_pcap is %d and net_pcap is %x\n",net_is_pcap,net_pcap); + } + } //end pcap setup + + //timer_add(slirp_tic,&delay,TIMER_ALWAYS_ENABLED,NULL); + //timer_add(keyboard_amstrad_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +pclog("ne2000 is_slirp %d is_pcap %d\n",net_is_slirp,net_is_pcap); +//exit(0); +return ne2000; +} + +void ne2000_close(void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + ne2000_io_remove(io_base, ne2000); + free(ne2000); +if(net_is_slirp) { + QueueDestroy(slirpq); + slirp_exit(0); + net_slirp_inited=0; + pclog("ne2000 exiting slirp\n"); + } +if(net_is_pcap && net_pcap!=NULL) + { + _pcap_close(net_pcap); + FreeLibrary(net_hLib); + pclog("ne2000 closing pcap\n"); + } +pclog("ne2000 close\n"); +} + +static device_config_t ne2000_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x280", + .value = 0x280 + }, + { + .description = "0x300", + .value = 0x300 + }, + { + .description = "0x320", + .value = 0x320 + }, + { + .description = "0x340", + .value = 0x340 + }, + { + .description = "0x360", + .value = 0x360 + }, + { + .description = "0x380", + .value = 0x380 + }, + { + .description = "" + } + }, + .default_int = 0x300 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { + .description = "IRQ 11", + .value = 11 + }, + { + .description = "" + } + }, + .default_int = 10 + }, + { + .name = "net_type", + .description = "Network type", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "PCap", + .value = 0 + }, + { + .description = "SLiRP", + .value = 1 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .name = "disable_netbios", + .description = "Network bios", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Enabled", + .value = 0 + }, + { + .description = "Disabled", + .value = 1 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .type = -1 + } +}; + +static device_config_t rtl8029as_config[] = +{ + { + .name = "net_type", + .description = "Network type", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "PCap", + .value = 0 + }, + { + .description = "SLiRP", + .value = 1 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .name = "disable_netbios", + .description = "Network bios", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Enabled", + .value = 0 + }, + { + .description = "Disabled", + .value = 1 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .type = -1 + } +}; + +device_t ne2000_device = +{ + "Novell NE2000", + 0, + ne2000_init, + ne2000_close, + NULL, + NULL, + NULL, + NULL, + ne2000_config +}; + +device_t rtl8029as_device = +{ + "Realtek RTL8029AS", + 0, + ne2000_init, + ne2000_close, + NULL, + NULL, + NULL, + NULL, + rtl8029as_config +}; + + +//SLIRP stuff +int slirp_can_output(void) +{ +return net_slirp_inited; +} + +void slirp_output (const unsigned char *pkt, int pkt_len) +{ +struct queuepacket *p; +p=(struct queuepacket *)malloc(sizeof(struct queuepacket)); +p->len=pkt_len; +memcpy(p->data,pkt,pkt_len); +QueueEnter(slirpq,p); +pclog("ne2000 slirp_output %d @%d\n",pkt_len,p); +} + +// Instead of calling this and crashing some times +// or experencing jitter, this is called by the +// 60Hz clock which seems to do the job. +void slirp_tic() +{ + int ret2,nfds; + struct timeval tv; + fd_set rfds, wfds, xfds; + int timeout; + nfds=-1; + + if(net_slirp_inited) + { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + timeout=slirp_select_fill(&nfds,&rfds,&wfds,&xfds); //this can crash + + if(timeout<0) + timeout=500; + tv.tv_sec=0; + tv.tv_usec = timeout; //basilisk default 10000 + + ret2 = select(nfds + 1, &rfds, &wfds, &xfds, &tv); + if(ret2>=0){ + slirp_select_poll(&rfds, &wfds, &xfds); + } + //pclog("ne2000 slirp_tic()\n"); + }//end if slirp inited +} diff --git a/src/ne2000.h b/src/ne2000.h new file mode 100644 index 000000000..dccfc79f7 --- /dev/null +++ b/src/ne2000.h @@ -0,0 +1,2 @@ +extern device_t ne2000_device; +extern device_t rtl8029as_device; diff --git a/src/neat.c b/src/neat.c new file mode 100644 index 000000000..23c72695d --- /dev/null +++ b/src/neat.c @@ -0,0 +1,68 @@ +/*This is the chipset used in the AMI 286 clone model*/ +#include "ibm.h" +#include "io.h" +#include "neat.h" + +static uint8_t neat_regs[256]; +static int neat_index; +static int neat_emspage[4]; + +void neat_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port) + { + case 0x22: + neat_index = val; + break; + + case 0x23: + neat_regs[neat_index] = val; + switch (neat_index) + { + case 0x6E: /*EMS page extension*/ + neat_emspage[3] = (neat_emspage[3] & 0x7F) | (( val & 3) << 7); + neat_emspage[2] = (neat_emspage[2] & 0x7F) | (((val >> 2) & 3) << 7); + neat_emspage[1] = (neat_emspage[1] & 0x7F) | (((val >> 4) & 3) << 7); + neat_emspage[0] = (neat_emspage[0] & 0x7F) | (((val >> 6) & 3) << 7); + break; + } + break; + + case 0x0208: case 0x0209: case 0x4208: case 0x4209: + case 0x8208: case 0x8209: case 0xC208: case 0xC209: + neat_emspage[port >> 14] = (neat_emspage[port >> 14] & 0x180) | (val & 0x7F); + break; + } +} + +uint8_t neat_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x22: + return neat_index; + + case 0x23: + return neat_regs[neat_index]; + } + return 0xff; +} + +void neat_writeems(uint32_t addr, uint8_t val) +{ + ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)] = val; +} + +uint8_t neat_readems(uint32_t addr) +{ + return ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)]; +} + +void neat_init() +{ + io_sethandler(0x0022, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0x0208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0x4208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0x8208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0xc208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); +} diff --git a/src/neat.h b/src/neat.h new file mode 100644 index 000000000..d87232243 --- /dev/null +++ b/src/neat.h @@ -0,0 +1 @@ +void neat_init(); diff --git a/src/nethandler.c b/src/nethandler.c new file mode 100644 index 000000000..1bd84b25b --- /dev/null +++ b/src/nethandler.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include +#include "nethandler.h" + +#include "ibm.h" +#include "device.h" + +#include "ne2000.h" +#include "timer.h" + +int network_card_current = 0; +static int network_card_last = 0; + +typedef struct +{ + char name[32]; + device_t *device; +} NETWORK_CARD; + +static NETWORK_CARD network_cards[] = +{ + {"None", NULL}, + {"Novell NE2000", &ne2000_device}, + {"Realtek RTL8029AS", &rtl8029as_device}, + {"", NULL} +}; + +int network_card_available(int card) +{ + if (network_cards[card].device) + return device_available(network_cards[card].device); + + return 1; +} + +char *network_card_getname(int card) +{ + return network_cards[card].name; +} + +device_t *network_card_getdevice(int card) +{ + return network_cards[card].device; +} + +int network_card_has_config(int card) +{ + if (!network_cards[card].device) + return 0; + return network_cards[card].device->config ? 1 : 0; +} + +void network_card_init() +{ + if (network_cards[network_card_current].device) + device_add(network_cards[network_card_current].device); + network_card_last = network_card_current; +} + +static struct +{ + void (*poller)(void *p); + void *priv; +} vlan_handlers[8]; + +static int vlan_handlers_num; + +static int vlan_poller_time = 0; + +void vlan_handler(void (*poller)(void *p), void *p) +//void vlan_handler(int (*can_receive)(void *p), void (*receive)(void *p, const uint8_t *buf, int size), void *p) +{ + /* vlan_handlers[vlan_handlers_num].can_receive = can_receive; */ + vlan_handlers[vlan_handlers_num].poller = poller; + vlan_handlers[vlan_handlers_num].priv = p; + vlan_handlers_num++; +} + +void vlan_poller(void *priv) +{ + int c; + + vlan_poller_time += (int)((double)TIMER_USEC * (1000000.0 / 8.0 / 1500.0)); + + for (c = 0; c < vlan_handlers_num; c++) + vlan_handlers[c].poller(vlan_handlers[c].priv); +} + +void vlan_reset() +{ + timer_add(vlan_poller, &vlan_poller_time, TIMER_ALWAYS_ENABLED, NULL); + + vlan_handlers_num = 0; +} diff --git a/src/nethandler.h b/src/nethandler.h new file mode 100644 index 000000000..d73ffb272 --- /dev/null +++ b/src/nethandler.h @@ -0,0 +1,15 @@ +#include + +//void vlan_handler(int (*can_receive)(void *p), void (*receive)(void *p, const uint8_t *buf, int size), void *p); +void vlan_handler(void (*poller)(void *p), void *p); + +extern int network_card_current; + +int network_card_available(int card); +char *network_card_getname(int card); +struct device_t *network_card_getdevice(int card); +int network_card_has_config(int card); +void network_card_init(); + +void initpcap(); +void closepcap(); diff --git a/src/nmi.c b/src/nmi.c new file mode 100644 index 000000000..5b8205328 --- /dev/null +++ b/src/nmi.c @@ -0,0 +1,15 @@ +#include "ibm.h" +#include "nmi.h" + +int nmi_mask; + +void nmi_write(uint16_t port, uint8_t val, void *p) +{ + nmi_mask = val & 0x80; +} + +void nmi_init() +{ + io_sethandler(0x00a0, 0x0001, NULL, NULL, NULL, nmi_write, NULL, NULL, NULL); + nmi_mask = 0; +} diff --git a/src/nmi.h b/src/nmi.h new file mode 100644 index 000000000..8e38a2c6a --- /dev/null +++ b/src/nmi.h @@ -0,0 +1,5 @@ +void nmi_init(); +void nmi_write(uint16_t port, uint8_t val, void *p); +extern int nmi_mask; + + diff --git a/src/nvr.c b/src/nvr.c new file mode 100644 index 000000000..13efe84f4 --- /dev/null +++ b/src/nvr.c @@ -0,0 +1,489 @@ +#include +#include "ibm.h" +#include "io.h" +#include "nvr.h" +#include "pic.h" +#include "timer.h" + +int oldromset; +int nvrmask=63; +uint8_t nvrram[128]; +int nvraddr; + +int nvr_dosave = 0; + +static int nvr_onesec_time = 0, nvr_onesec_cnt = 0; + +int enable_sync = 0; + +#define second internal_time[0] +#define minute internal_time[1] +#define hour internal_time[2] +#define day internal_time[3] +#define month internal_time[4] +#define year internal_time[5] +int internal_time[6]; +int days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +static int is_leap(int org_year) +{ + if (org_year % 400 == 0) return 1; + if (org_year % 100 == 0) return 0; + if (org_year % 4 == 0) return 1; + return 0; +} + +static int get_days(int org_month, int org_year) +{ + if (org_month != 2) + { + return days_in_month[org_month]; + } + else + { + return is_leap(org_year) ? 29 : 28; + } +} + +static int convert_to_bcd(int number) +{ + int n1, n2; + n1 = number % 10; + n2 = number - n1; + n2 /= 10; + n2 <<= 4; + return (n2 | n1); +} + +static int convert_from_bcd(int number) +{ + int n1, n2; + n1 = number & 0xF; + n2 = number >> 4; + n2 *= 10; + return (n2 + n1); +} + +static int final_form(int isbcd, int number) +{ + return isbcd ? convert_to_bcd(number) : number; +} + +static int original_form(int isbcd, int number) +{ + return isbcd ? convert_from_bcd(number) : number; +} + +static void nvr_recalc_clock() +{ + if (second == 60) + { + second = 0; + minute++; + } + if (minute == 60) + { + minute = 0; + hour++; + } + if (hour == 24) + { + hour = 0; + day++; + } + if (day == (get_days(month, year) + 1)) + { + day = 1; + month++; + } + if (month == 13) + { + month = 1; + year++; + } + nvr_dosave = 1; +} + +static void nvr_update_internal_clock() +{ + second++; + nvr_recalc_clock(); +} + +void nvr_add_10sec() +{ + time_sleep(10000); + if (!enable_sync) + { + second+=10; + nvr_recalc_clock(); + } +} + +static int to_12_hour(int org_hour) +{ + int hour2 = org_hour; + hour2 %= 12; + if (!hour2) hour2 = 12; + return hour2; +} + +static int from_12_hour(int org_hour) +{ + int hour2 = org_hour & 0x7F; + if (hour2 == 12) hour2 = 0; + if (hour & 0x80) hour2 += 12; + return hour2; +} + +static int week_day() +{ + int day_of_month = day; + int month2 = month; + int year2 = year % 100; + int century = ((year - year2) / 100) % 4; + int sum = day_of_month + month2 + year2 + century; + /* (sum mod 7) gives 0 for Saturday, we need it for Monday, so +5 */ + int raw_wd = ((sum + 5) % 7); + /* +1 so 1 = Monday, 7 = Sunday */ + return raw_wd + 1; +} + +/* Called on every get time. */ +static void set_registers() +{ + int is24hour = (nvrram[0xB] & 2) ? 1 : 0; + int isbcd = (nvrram[0xB] & 4) ? 0 : 1; + + uint8_t baknvr[10]; + + memcpy(baknvr,nvrram,10); + + if (AMSTRAD) + { + is24hour = 1; + isbcd = 1; + } + + nvrram[0] = final_form(isbcd, second); + nvrram[2] = final_form(isbcd, minute); + nvrram[4] = is24hour ? final_form(isbcd, hour) : final_form(isbcd, to_12_hour(hour)); + nvrram[6] = week_day(); + nvrram[7] = final_form(isbcd, day); + nvrram[8] = final_form(isbcd, month); + nvrram[9] = final_form(isbcd, (year % 100)); + + if (baknvr[0] != nvrram[0] || + baknvr[2] != nvrram[2] || + baknvr[4] != nvrram[4] || + baknvr[6] != nvrram[6] || + baknvr[7] != nvrram[7] || + baknvr[8] != nvrram[8] || + baknvr[9] != nvrram[9]) + nvrram[0xA]|=0x80; +} + +/* Called on NVR load and write. */ +static void get_registers() +{ + int is24hour = (nvrram[0xB] & 2) ? 1 : 0; + int isbcd = (nvrram[0xB] & 4) ? 0 : 1; + + int temp_hour = 0; + + if (AMSTRAD) + { + is24hour = 1; + isbcd = 1; + } + + second = original_form(isbcd, nvrram[0]); + minute = original_form(isbcd, nvrram[2]); + hour = is24hour ? original_form(isbcd, nvrram[4]) : from_12_hour(original_form(isbcd, nvrram[4])); + day = original_form(isbcd, nvrram[7]); + month = original_form(isbcd, nvrram[8]); + year = original_form(isbcd, nvrram[9]) + 1900; +} + +void getnvrtime() +{ + if (enable_sync) + { + /* Get time from host. */ + time_get(nvrram); + } + else + { + /* Get time from internal clock. */ + set_registers(); + } +} + +void update_sync() +{ + if (enable_sync) + { + /* Get time from host. */ + time_get(nvrram); + } + else + { + /* Save time to registers but keep it as is. */ + get_registers(); + } +} + +void nvr_recalc() +{ + int c; + int newrtctime; + c=1<<((nvrram[0xA]&0xF)-1); + newrtctime=(int)(RTCCONST * c * (1 << TIMER_SHIFT)); + if (rtctime>newrtctime) rtctime=newrtctime; +} + +void nvr_rtc(void *p) +{ + int c; + if (!(nvrram[0xA]&0xF)) + { + rtctime=0x7fffffff; + return; + } + c=1<<((nvrram[0xA]&0xF)-1); + rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); +// pclog("RTCtime now %f\n",rtctime); + nvrram[0xC] |= 0x40; + if (nvrram[0xB]&0x40) + { + nvrram[0xC]|=0x80; + if (AMSTRAD) picint(2); + else picint(0x100); +// pclog("RTC int\n"); + } +} + +void nvr_onesec(void *p) +{ + nvr_onesec_cnt++; + if (nvr_onesec_cnt >= 100) + { + nvr_onesec_cnt = 0; + /* If sync is disabled, move internal clock ahead by 1 second. */ + if (!enable_sync) nvr_update_internal_clock(); + nvrram[0xC] |= 0x10; + if (nvrram[0xB] & 0x10) + { + nvrram[0xC] |= 0x80; + if (AMSTRAD) picint(2); + else picint(0x100); + } +// pclog("RTC onesec\n"); + } + nvr_onesec_time += (int)(10000 * TIMER_USEC); +} + +void writenvr(uint16_t addr, uint8_t val, void *priv) +{ + int c, old; +// printf("Write NVR %03X %02X %02X %04X:%04X %i\n",addr,nvraddr,val,cs>>4,pc,ins); + if (addr&1) + { +// if (nvraddr == 0x33) pclog("NVRWRITE33 %02X %04X:%04X %i\n",val,CS,pc,ins); + old = nvrram[nvraddr]; + if (nvraddr >= 0xe && nvrram[nvraddr] != val) + nvr_dosave = 1; + // if (nvraddr==0xB) update_reg_0B(val); + if (nvraddr!=0xC && nvraddr!=0xD) nvrram[nvraddr]=val; + + /* If not syncing the time with the host, we need to update our internal clock on write. */ + if (!enable_sync) + { + switch(nvraddr) + { + case 0: + case 2: + case 4: + case 6: + case 7: + case 8: + case 9: + if (old != val) + { + get_registers(); + nvr_dosave = 1; + } + return; + } + } + + if (nvraddr==0xA) + { +// pclog("NVR rate %i\n",val&0xF); + if (val&0xF) + { + c=1<<((val&0xF)-1); + rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); + } + else + rtctime = 0x7fffffff; + } + } + else nvraddr=val&nvrmask; +} + +uint8_t readnvr(uint16_t addr, void *priv) +{ + uint8_t temp; +// printf("Read NVR %03X %02X %02X %04X:%04X\n",addr,nvraddr,nvrram[nvraddr],cs>>4,pc); + if (addr&1) + { + if (nvraddr<=0xA) getnvrtime(); + if (nvraddr==0xD) nvrram[0xD]|=0x80; + if (nvraddr==0xA) + { + temp=nvrram[0xA]; + nvrram[0xA]&=~0x80; + return temp; + } + if (nvraddr==0xC) + { + if (AMSTRAD) picintc(2); + else picintc(0x100); + temp=nvrram[0xC]; + nvrram[0xC]=0; + return temp; + } +// if (AMIBIOS && nvraddr==0x36) return 0; +// if (nvraddr==0xA) nvrram[0xA]^=0x80; + return nvrram[nvraddr]; + } + return nvraddr; +} + +void loadnvr() +{ + FILE *f; + int c; + nvrmask=63; + oldromset=romset; + switch (romset) + { + case ROM_PC1512: f = romfopen("nvr/pc1512.nvr", "rb"); break; + case ROM_PC1640: f = romfopen("nvr/pc1640.nvr", "rb"); break; + case ROM_PC200: f = romfopen("nvr/pc200.nvr", "rb"); break; + case ROM_PC2086: f = romfopen("nvr/pc2086.nvr", "rb"); break; + case ROM_PC3086: f = romfopen("nvr/pc3086.nvr", "rb"); break; + case ROM_IBMAT: f = romfopen("nvr/at.nvr", "rb"); break; + case ROM_IBMPS1_2011: f = romfopen("nvr/ibmps1_2011.nvr", "rb"); /*nvrmask = 127; */break; + case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "rb"); nvrmask = 127; break; + case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "rb"); nvrmask = 127; break; + case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "rb"); nvrmask = 127; break; + case ROM_DELL200: f = romfopen("nvr/dell200.nvr", "rb"); nvrmask = 127; break; + case ROM_IBMAT386: f = romfopen("nvr/at386.nvr", "rb"); nvrmask = 127; break; + case ROM_DESKPRO_386: f = romfopen("nvr/deskpro386.nvr", "rb"); break; + case ROM_ACER386: f = romfopen("nvr/acer386.nvr", "rb"); nvrmask = 127; break; + case ROM_MEGAPC: f = romfopen("nvr/megapc.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI386: f = romfopen("nvr/ami386.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI486: f = romfopen("nvr/ami486.nvr", "rb"); nvrmask = 127; break; + case ROM_WIN486: f = romfopen("nvr/win486.nvr", "rb"); nvrmask = 127; break; + case ROM_PCI486: f = romfopen("nvr/hot-433.nvr", "rb"); nvrmask = 127; break; + case ROM_SIS496: f = romfopen("nvr/sis496.nvr", "rb"); nvrmask = 127; break; + case ROM_430VX: f = romfopen("nvr/430vx.nvr", "rb"); nvrmask = 127; break; + case ROM_REVENGE: f = romfopen("nvr/revenge.nvr", "rb"); nvrmask = 127; break; + case ROM_ENDEAVOR: f = romfopen("nvr/endeavor.nvr", "rb"); nvrmask = 127; break; + case ROM_PX386: f = romfopen("nvr/px386.nvr", "rb"); nvrmask = 127; break; + case ROM_DTK386: f = romfopen("nvr/dtk386.nvr", "rb"); nvrmask = 127; break; + case ROM_DTK486: f = romfopen("nvr/dtk486.nvr", "rb"); nvrmask = 127; break; + case ROM_R418: f = romfopen("nvr/r418.nvr", "rb"); nvrmask = 127; break; + case ROM_586MC1: f = romfopen("nvr/586mc1.nvr", "rb"); nvrmask = 127; break; + case ROM_PLATO: f = romfopen("nvr/plato.nvr", "rb"); nvrmask = 127; break; + case ROM_MB500N: f = romfopen("nvr/mb500n.nvr", "rb"); nvrmask = 127; break; + case ROM_P54TP4XE: f = romfopen("nvr/p54tp4xe.nvr", "rb"); nvrmask = 127; break; + case ROM_ACERM3A: f = romfopen("nvr/acerm3a.nvr", "rb"); nvrmask = 127; break; + case ROM_ACERV35N: f = romfopen("nvr/acerv35n.nvr", "rb"); nvrmask = 127; break; + case ROM_P55T2P4: f = romfopen("nvr/p55t2p4.nvr", "rb"); nvrmask = 127; break; + case ROM_P55TVP4: f = romfopen("nvr/p55tvp4.nvr", "rb"); nvrmask = 127; break; + case ROM_P55VA: f = romfopen("nvr/p55va.nvr", "rb"); nvrmask = 127; break; + case ROM_440FX: f = romfopen("nvr/440fx.nvr", "rb"); nvrmask = 127; break; + case ROM_KN97: f = romfopen("nvr/kn97.nvr", "rb"); nvrmask = 127; break; + default: return; + } + if (!f) + { + memset(nvrram,0xFF,128); + return; + } + fread(nvrram,128,1,f); + if (!(feof(f))) + fread(internal_time,6,4,f); + else + { + if (!enable_sync) get_registers(); + } + fclose(f); + nvrram[0xA]=6; + nvrram[0xB]=0; + c=1<<((6&0xF)-1); + rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); +} +void savenvr() +{ + FILE *f; + switch (oldromset) + { + case ROM_PC1512: f = romfopen("nvr/pc1512.nvr", "wb"); break; + case ROM_PC1640: f = romfopen("nvr/pc1640.nvr", "wb"); break; + case ROM_PC200: f = romfopen("nvr/pc200.nvr", "wb"); break; + case ROM_PC2086: f = romfopen("nvr/pc2086.nvr", "wb"); break; + case ROM_PC3086: f = romfopen("nvr/pc3086.nvr", "wb"); break; + case ROM_IBMAT: f = romfopen("nvr/at.nvr", "wb"); break; + case ROM_IBMPS1_2011: f = romfopen("nvr/ibmps1_2011.nvr", "wb"); break; + case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "wb"); break; + case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "wb"); break; + case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "wb"); break; + case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "wb"); break; + case ROM_DELL200: f = romfopen("nvr/dell200.nvr", "wb"); break; + case ROM_IBMAT386: f = romfopen("nvr/at386.nvr", "wb"); break; + case ROM_DESKPRO_386: f = romfopen("nvr/deskpro386.nvr", "wb"); break; + case ROM_ACER386: f = romfopen("nvr/acer386.nvr", "wb"); break; + case ROM_MEGAPC: f = romfopen("nvr/megapc.nvr", "wb"); break; + case ROM_AMI386: f = romfopen("nvr/ami386.nvr", "wb"); break; + case ROM_AMI486: f = romfopen("nvr/ami486.nvr", "wb"); break; + case ROM_WIN486: f = romfopen("nvr/win486.nvr", "wb"); break; + case ROM_PCI486: f = romfopen("nvr/hot-433.nvr", "wb"); break; + case ROM_SIS496: f = romfopen("nvr/sis496.nvr", "wb"); break; + case ROM_430VX: f = romfopen("nvr/430vx.nvr", "wb"); break; + case ROM_REVENGE: f = romfopen("nvr/revenge.nvr", "wb"); break; + case ROM_ENDEAVOR: f = romfopen("nvr/endeavor.nvr", "wb"); break; + case ROM_PX386: f = romfopen("nvr/px386.nvr", "wb"); break; + case ROM_DTK386: f = romfopen("nvr/dtk386.nvr", "wb"); break; + case ROM_DTK486: f = romfopen("nvr/dtk486.nvr", "wb"); break; + case ROM_R418: f = romfopen("nvr/r418.nvr", "wb"); break; + case ROM_586MC1: f = romfopen("nvr/586mc1.nvr", "wb"); break; + case ROM_PLATO: f = romfopen("nvr/plato.nvr", "wb"); break; + case ROM_MB500N: f = romfopen("nvr/mb500n.nvr", "wb"); break; + case ROM_P54TP4XE: f = romfopen("nvr/p54tp4xe.nvr", "wb"); break; + case ROM_ACERM3A: f = romfopen("nvr/acerm3a.nvr", "wb"); break; + case ROM_ACERV35N: f = romfopen("nvr/acerv35n.nvr", "wb"); break; + case ROM_P55T2P4: f = romfopen("nvr/p55t2p4.nvr", "wb"); break; + case ROM_P55TVP4: f = romfopen("nvr/p55tvp4.nvr", "wb"); break; + case ROM_P55VA: f = romfopen("nvr/p55va.nvr", "wb"); break; + case ROM_440FX: f = romfopen("nvr/440fx.nvr", "wb"); break; + case ROM_KN97: f = romfopen("nvr/kn97.nvr", "wb"); break; + default: return; + } + /* If sync is disabled, save internal clock to registers. */ + if (!enable_sync) set_registers(); + fwrite(nvrram,128,1,f); + fwrite(internal_time,6,4,f); + fclose(f); +} + +void nvr_init() +{ + io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL, NULL); + timer_add(nvr_rtc, &rtctime, TIMER_ALWAYS_ENABLED, NULL); + timer_add(nvr_onesec, &nvr_onesec_time, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/nvr.h b/src/nvr.h new file mode 100644 index 000000000..fe3c72e1b --- /dev/null +++ b/src/nvr.h @@ -0,0 +1,11 @@ +void nvr_init(); + +extern int nvr_dosave; +extern int enable_sync; + +void time_sleep(int count); + +void time_get(char *nvrram); +void nvr_add_10sec(); + +void update_sync(); diff --git a/src/olivetti_m24.c b/src/olivetti_m24.c new file mode 100644 index 000000000..72f08a373 --- /dev/null +++ b/src/olivetti_m24.c @@ -0,0 +1,20 @@ +#include "ibm.h" +#include "io.h" +#include "olivetti_m24.h" + +uint8_t olivetti_m24_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x66: + return 0x00; + case 0x67: + return 0x20 | 0x40 | 0x0C; + } + return 0xff; +} + +void olivetti_m24_init() +{ + io_sethandler(0x0066, 0x0002, olivetti_m24_read, NULL, NULL, NULL, NULL, NULL, NULL); +} diff --git a/src/olivetti_m24.h b/src/olivetti_m24.h new file mode 100644 index 000000000..7475072f0 --- /dev/null +++ b/src/olivetti_m24.h @@ -0,0 +1 @@ +void olivetti_m24_init(); diff --git a/src/opti.c b/src/opti.c new file mode 100644 index 000000000..392837e05 --- /dev/null +++ b/src/opti.c @@ -0,0 +1,284 @@ +/*OPTi 82C495 emulation + This is the chipset used in the AMI386 model*/ +#include "ibm.h" + +uint8_t optiregs[0x10]; +int optireg; + +void writeopti(uint16_t addr, uint8_t val) +{ + switch (addr) + { + case 0x22: + optireg=val; + break; + case 0x24: + printf("Writing OPTI reg %02X %02X\n",optireg,val); + if (optireg>=0x20 && optireg<=0x2C) optiregs[optireg-0x20]=val; + break; + } +} + +uint8_t readopti(uint16_t addr) +{ + switch (addr) + { + case 0x24: + printf("Read OPTI reg %02X\n",optireg); + if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20]; + break; + } + return 0xFF; +} + +/*Details for the chipset from Ralph Brown's interrupt list + This describes the OPTi 82C493, the 82C495 seems similar except there is one + more register (2C) + +----------P00220024-------------------------- +PORT 0022-0024 - OPTi 82C493 System Controller (SYSC) - CONFIGURATION REGISTERS +Desc: The OPTi 486SXWB contains three chips and is designed for systems + running at 20, 25 and 33MHz. The chipset includes an 82C493 System + Controller (SYSC), the 82C392 Data Buffer Controller, and the + 82C206 Integrated peripheral Controller (IPC). +Note: every access to PORT 0024h must be preceded by a write to PORT 0022h, + even if the same register is being accessed a second time +SeeAlso: PORT 0022h"82C206" + +0022 ?W configuration register index (see #P0178) +0024 RW configuration register data + +(Table P0178) +Values for OPTi 82C493 System Controller configuration register index: + 20h Control Register 1 (see #P0179) + 21h Control Register 2 (see #P0180) + 22h Shadow RAM Control Register 1 (see #P0181) + 23h Shadow RAM Control Register 2 (see #P0182) + 24h DRAM Control Register 1 (see #P0183) + 25h DRAM Control Register 2 (see #P0184) + 26h Shadow RAM Control Register 3 (see #P0185) + 27h Control Register 3 (see #P0186) + 28h Non-cachable Block 1 Register 1 (see #P0187) + 29h Non-cachable Block 1 Register 2 (see #P0188) + 2Ah Non-cachable Block 2 Register 1 (see #P0187) + 2Bh Non-cachable Block 2 Register 2 (see #P0188) + +Bitfields for OPTi-82C493 Control Register 1: +Bit(s) Description (Table P0179) + 7-6 Revision of 82C493 (readonly) (default=01) + 5 Burst wait state control + 1 = Secondary cache read hit cycle is 3-2-2-2 or 2-2-2-2 + 0 = Secondary cache read hit cycle is 3-1-1-1 or 2-1-1-1 (default) + (if bit 5 is set to 1, bit 4 must be set to 0) + 4 Cache memory data buffer output enable control + 0 = disable (default) + 1 = enable + (must be disabled for frequency <= 33Mhz) + 3 Single Address Latch Enable (ALE) + 0 = disable (default) + 1 = enable + (if enabled, SYSC will activate single ALE rather than multiples + during bus conversion cycles) + 2 enable Extra AT Cycle Wait State (default is 0 = disabled) + 1 Emulation keyboard Reset Control + 0 = disable (default) + 1 = enable + Note: This bit must be enabled in BIOS default value; enabling this + bit requires HALT instruction to be executed before SYSC + generates processor reset (CPURST) + 0 enable Alternative Fast Reset (default is 0 = disabled) +SeeAlso: #P0180,#P0186 + +Bitfields for OPTi-82C493 Control Register 2: +Bit(s) Description (Table P0180) + 7 Master Mode Byte Swap Enable + 0 = disable (default) + 1 = enable + 6 Emulation Keyboard Reset Delay Control + 0 = Generate reset pulse 2us later (default) + 1 = Generate reset pulse immediately + 5 disable Parity Check (default is 0 = enabled) + 4 Cache Enable + 0 = Cache disabled and DRAM burst mode enabled (default) + 1 = Cache enabled and DRAM burst mode disabled + 3-2 Cache Size + 00 64KB (default) + 01 128KB + 10 256KB + 11 512KB + 1 Secondary Cache Read Burst Cycles Control + 0 = 3-1-1-1 cycle (default) + 1 = 2-1-1-1 cycle + 0 Cache Write Wait State Control + 0 = 1 wait state (default) + 1 = 0 wait state +SeeAlso: #P0179,#P0186 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 1: +Bit(s) Description (Table P0181) + 7 ROM(F0000h - FFFFFh) Enable + 0 = read/write on write-protected DRAM + 1 = read from ROM, write to DRAM (default) + 6 Shadow RAM at D0000h - EFFFFh Area + 0 = disable (default) + 1 = enable + 5 Shadow RAM at E0000h - EFFFFh Area + 0 = disable shadow RAM (default) + E0000h - EFFFFh ROM is defaulted to reside on XD bus + 1 = enable shadow RAM + 4 enable write-protect for Shadow RAM at D0000h - DFFFFh Area + 0 = disable (default) + 1 = enable + 3 enable write-protect for Shadow RAM at E0000h - EFFFFh Area + 0 = disable (default) + 1 = enable + 2 Hidden refresh enable (with holding CPU) + (Hidden refresh must be disabled if 4Mx1 or 1M x4 bit DRAM are used) + 1 = disable (default) + 0 = enable + 1 unused + 0 enable Slow Refresh (four times slower than normal refresh) + (default is 0 = disable) +SeeAlso: #P0182 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 2: +Bit(s) Description (Table P0182) + 7 enable Shadow RAM at EC000h - EFFFFh area + 6 enable Shadow RAM at E8000h - EBFFFh area + 5 enable Shadow RAM at E4000h - E7FFFh area + 4 enable Shadow RAM at E0000h - E3FFFh area + 3 enable Shadow RAM at DC000h - DFFFFh area + 2 enable Shadow RAM at D8000h - DBFFFh area + 1 enable Shadow RAM at D4000h - D7FFFh area + 0 enable Shadow RAM at D0000h - D3FFFh area +Note: the default is disabled (0) for all areas + +Bitfields for OPTi-82C493 DRAM Control Register 1: +Bit(s) Description (Table P0183) + 7 DRAM size + 0 = 256K DRAM mode + 1 = 1M and 4M DRAM mode + 6-4 DRAM types used for bank0 and bank1 + bits 7-4 Bank0 Bank1 + 0000 256K x + 0001 256K 256K + 0010 256K 1M + 0011 x x + 01xx x x + 1000 1M x (default) + 1001 1M 1M + 1010 1M 4M + 1011 4M 1M + 1100 4M x + 1101 4M 4M + 111x x x + 3 unused + 2-0 DRAM types used for bank2 and bank3 + bits 7,2-0 Bank2 Bank3 + x000 1M x + x001 1M 1M + x010 x x + x011 4M 1M + x100 4M x + x101 4M 4M + x11x x x (default) +SeeAlso: #P0184 + +Bitfields for OPTi-82C493 DRAM Control Register 2: +Bit(s) Description (Table P0184) + 7-6 Read cycle additional wait states + 00 not used + 01 = 0 + 10 = 1 + 11 = 2 (default) + 5-4 Write cycle additional wait states + 00 = 0 + 01 = 1 + 10 = 2 + 11 = 3 (default) + 3 Fast decode enable + 0 = disable fast decode. DRAM base wait states not changed (default) + 1 = enable fast decode. DRAM base wait state is decreased by 1 + Note: This function may be enabled in 20/25Mhz operation to speed up + DRAM access. If bit 4 of index register 21h (cache enable + bit) is enabled, this bit is automatically disabled--even if + set to 1 + 2 unused + 1-0 ATCLK selection + 00 ATCLK = CLKI/6 (default) + 01 ATCLK = CLKI/4 (default) + 10 ATCLK = CLKI/3 + 11 ATCLK = CLK2I/5 (CLKI * 2 /5) + Note: bit 0 will reflect the BCLKS (pin 142) status and bit 1 will be + set to 0 when 82C493 is reset. +SeeAlso: #P0183,#P0185 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 3: +Bit(s) Description (Table P0185) + 7 unused + 6 Shadow RAM copy enable for address C0000h - CFFFFh + 0 = Read/write at AT bus (default) + 1 = Read from AT bus and write into shadow RAM + 5 Shadow write protect at address C0000h - CFFFFh + 0 = Write protect disable (default) + 1 = Write protect enable + 4 enable Shadow RAM at C0000h - CFFFFh + 3 enable Shadow RAM at CC000h - CFFFFh + 2 enable Shadow RAM at C8000h - CBFFFh + 1 enable Shadow RAM at C4000h - C7FFFh + 0 enable Shadow RAM at C0000h - C3FFFh +Note: the default is disabled (0) for bits 4-0 +SeeAlso: #P0183,#P0184 + +Bitfields for OPTi-82C493 Control Register 3: +Bit(s) Description (Table P0186) + 7 enable NCA# pin to low state (default is 1 = enabled) + 6-5 unused + 4 Video BIOS at C0000h - C8000h non-cacheable + 0 = cacheable + 1 = non-cacheable (default) + 3-0 Cacheable address range for local memory + 0000 0 - 64MB + 0001 0 - 4MB (default) + 0010 0 - 8MB + 0011 0 - 12MB + 0100 0 - 16MB + 0101 0 - 20MB + 0110 0 - 24MB + 0111 0 - 28MB + 1000 0 - 32MB + 1001 0 - 36MB + 1010 0 - 40MB + 1011 0 - 44MB + 1100 0 - 48MB + 1101 0 - 52MB + 1110 0 - 56MB + 1111 0 - 60MB + Note: If total memory is 1MB or 2MB the cacheable range is 0-1 MB or + 0-2 MB and independent of the value of bits 3-0 +SeeAlso: #P0179,#P0180 + +Bitfields for OPTi-82C493 Non-cacheable Block Register 1: +Bit(s) Description (Table P0187) + 7-5 Size of non-cachable memory block + 000 64K + 001 128K + 010 256K + 011 512K + 1xx disabled (default) + 4-2 unused + 1-0 Address bits 25 and 24 of non-cachable memory block (default = 00) +Note: this register is used together with configuration register 29h + (non-cacheable block 1) or register 2Bh (block 2) (see #P0188) to + define a non-cacheable block. The starting address must be a + multiple of the block size +SeeAlso: #P0178,#P0188 + +Bitfields for OPTi-82C493 Non-cacheable Block Register 2: +Bit(s) Description (Table P0188) + 7-0 Address bits 23-16 of non-cachable memory block (default = 0001xxxx) +Note: the block address is forced to be a multiple of the block size by + ignoring the appropriate number of the least-significant bits +SeeAlso: #P0178,#P0187 + +*/ diff --git a/src/pc.c b/src/pc.c new file mode 100644 index 000000000..c5a7b9441 --- /dev/null +++ b/src/pc.c @@ -0,0 +1,809 @@ +#include +#include +#include +#include "ibm.h" +#include "device.h" + +#include "ali1429.h" +#include "amstrad.h" +#include "cdrom-ioctl.h" +#include "disc.h" +#include "mem.h" +#include "x86_ops.h" +#include "codegen.h" +#include "cdrom-iso.h" +#include "cdrom-null.h" +#include "config.h" +#include "cpu.h" +#include "dma.h" +#include "fdc.h" +#include "fdd.h" +#include "gameport.h" +#include "sound_gus.h" +#include "ide.h" +#include "keyboard.h" +#include "keyboard_at.h" +#include "model.h" +#include "mouse.h" +#include "nvr.h" +#include "pic.h" +#include "pit.h" +#include "plat-joystick.h" +#include "plat-mouse.h" +#include "serial.h" +#include "sound.h" +#include "sound_cms.h" +#include "sound_opl.h" +#include "sound_sb.h" +#include "sound_ssi2001.h" +#include "timer.h" +#include "vid_voodoo.h" +#include "video.h" +#include "nethandler.h" +#define NE2000 1 +#define RTL8029AS 2 +uint8_t ethif; +int inum; + +int window_w, window_h, window_x, window_y, window_remember; + +int start_in_fullscreen = 0; +int frame = 0; + +int cdrom_enabled; +int CPUID; +int vid_resize, vid_api; + +int cycles_lost = 0; + +int clockrate; +int insc=0; +float mips,flops; +extern int mmuflush; +extern int readlnum,writelnum; +void fullspeed(); + +int framecount,fps; +int intcount; + +int output; +int atfullspeed; + +void saveconfig(); +int infocus; +int mousecapture; +// FILE *pclogf; +void pclog(const char *format, ...) +{ +#ifndef RELEASE_BUILD + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); +#endif +} + +void fatal(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + dumppic(); + dumpregs(); + fflush(stdout); + exit(-1); +} + +uint8_t cgastat; + +int pollmouse_delay = 2; +void pollmouse() +{ + int x,y; +// return; + pollmouse_delay--; + if (pollmouse_delay) return; + pollmouse_delay = 2; + mouse_poll_host(); + mouse_get_mickeys(&x,&y); + if (mouse_poll) + mouse_poll(x, y, mouse_buttons); +// if (mousecapture) position_mouse(64,64); +} + +/*PC1512 languages - + 7=English + 6=German + 5=French + 4=Spanish + 3=Danish + 2=Swedish + 1=Italian + 3,2,1 all cause the self test to fail for some reason + */ + +int cpuspeed2; + +int clocks[3][12][4]= +{ + { + {4772728,13920,59660,5965}, /*4.77MHz*/ + {8000000,23333,110000,0}, /*8MHz*/ + {10000000,29166,137500,0}, /*10MHz*/ + {12000000,35000,165000,0}, /*12MHz*/ + {16000000,46666,220000,0}, /*16MHz*/ + }, + { + {8000000,23333,110000,0}, /*8MHz*/ + {12000000,35000,165000,0}, /*12MHz*/ + {16000000,46666,220000,0}, /*16MHz*/ + {20000000,58333,275000,0}, /*20MHz*/ + {25000000,72916,343751,0}, /*25MHz*/ + }, + { + {16000000, 46666,220000,0}, /*16MHz*/ + {20000000, 58333,275000,0}, /*20MHz*/ + {25000000, 72916,343751,0}, /*25MHz*/ + {33000000, 96000,454000,0}, /*33MHz*/ + {40000000,116666,550000,0}, /*40MHz*/ + {50000000, 72916*2,343751*2,0}, /*50MHz*/ + {33000000*2, 96000*2,454000*2,0}, /*66MHz*/ + {75000000, 72916*3,343751*3,0}, /*75MHz*/ + {80000000,116666*2,550000*2,0}, /*80MHz*/ + {100000000, 72916*4,343751*4,0}, /*100MHz*/ + {120000000,116666*3,550000*3,0}, /*120MHz*/ + {133000000, 96000*4,454000*4,0}, /*133MHz*/ + } +}; + +int updatestatus; +int win_title_update=0; + + +void onesec() +{ + fps=framecount; + framecount=0; + win_title_update=1; +} + +void pc_reset() +{ + cpu_set(); + resetx86(); + mem_updatecache(); + //timer_reset(); + dma_reset(); + fdc_reset(); + pic_reset(); + pit_reset(); + serial_reset(); + + if (AT) + setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + else + setpitclock(14318184.0); + +// sb_reset(); + + ali1429_reset(); +// video_init(); +} +#undef printf +void initpc(int argc, char *argv[]) +{ + char *p; + char *config_file = NULL; + int c; + FILE *ff; +// allegro_init(); + get_executable_name(pcempath,511); + pclog("executable_name = %s\n", pcempath); + p=get_filename(pcempath); + *p=0; + pclog("path = %s\n", pcempath); + + for (c = 1; c < argc; c++) + { + if (!strcasecmp(argv[c], "--help")) + { + printf("PCem command line options :\n\n"); + printf("--config file.cfg - use given config file as initial configuration\n"); + printf("--fullscreen - start in fullscreen mode\n"); + exit(-1); + } + else if (!strcasecmp(argv[c], "--fullscreen")) + { + start_in_fullscreen = 1; + } + else if (!strcasecmp(argv[c], "--config")) + { + if ((c+1) == argc) + break; + config_file = argv[c+1]; + c++; + } + } + + keyboard_init(); + mouse_init(); + joystick_init(); + midi_init(); + + append_filename(config_file_default, pcempath, "pcem.cfg", 511); + + loadconfig(config_file); + pclog("Config loaded\n"); + if (config_file) + saveconfig(); + + codegen_init(); + + cpuspeed2=(AT)?2:1; +// cpuspeed2=cpuspeed; + atfullspeed=0; + + initvideo(); + mem_init(); + loadbios(); + mem_add_bios(); + + device_init(); + + timer_reset(); + sound_reset(); + fdc_init(); + disc_init(); + fdi_init(); + img_init(); + + vlan_reset(); //NETWORK + network_card_init(network_card_current); + + disc_load(0, discfns[0]); + disc_load(1, discfns[1]); + + //loadfont(); + loadnvr(); + sound_init(); + resetide(); + if ((cdrom_drive == -1) || (cdrom_drive == 0)) + cdrom_null_open(cdrom_drive); + else + { + if (cdrom_drive == 200) + { + ff = fopen(iso_path, "rb"); + if (ff) + { + fclose(ff); + iso_open(iso_path); + } + else + { +#if __unix + cdrom_drive = -1; +#else + cdrom_drive = 0; +#endif + cdrom_null_open(cdrom_drive); + } + } + else + { + ioctl_open(cdrom_drive); + } + } + + pit_reset(); +/* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed(); + ali1429_reset(); +// CPUID=(is486 && (cpuspeed==7 || cpuspeed>=9)); +// pclog("Init - CPUID %i %i\n",CPUID,cpuspeed); + shadowbios=0; + + if ((cdrom_drive == -1) || (cdrom_drive == 0)) + cdrom_null_reset(); + else + { + if (cdrom_drive == 200) + { + iso_reset(); + } + else + { + ioctl_reset(); + } + } +} + +void resetpc() +{ + pc_reset(); +// cpuspeed2=(AT)?2:1; +// atfullspeed=0; +///* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed(); + shadowbios=0; +} + +void pc_keyboard_send(uint8_t val) +{ + if (AT) + { + keyboard_at_adddata_keyboard_raw(val); + } + else + { + keyboard_send(val); + } +} + +void resetpc_cad() +{ + pc_keyboard_send(29); /* Ctrl key pressed */ + pc_keyboard_send(56); /* Alt key pressed */ + pc_keyboard_send(83); /* Delete key pressed */ + pc_keyboard_send(157); /* Ctrl key released */ + pc_keyboard_send(184); /* Alt key released */ + pc_keyboard_send(211); /* Delete key released */ +} + +void resetpchard() +{ + savenvr(); + + device_close_all(); + device_init(); + + midi_close(); + midi_init(); + + timer_reset(); + sound_reset(); + mem_resize(); + fdc_init(); + disc_reset(); + + model_init(); + // mem_add_bios(); + video_init(); + speaker_init(); + + vlan_reset(); //NETWORK + network_card_init(network_card_current); + + sound_card_init(sound_card_current); + if (GUS) + device_add(&gus_device); + if (GAMEBLASTER) + device_add(&cms_device); + if (SSI2001) + device_add(&ssi2001_device); + if (voodoo_enabled) + device_add(&voodoo_device); + pc_reset(); + + resetide(); + + loadnvr(); + +// cpuspeed2 = (AT)?2:1; +// atfullspeed = 0; +// setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + + shadowbios = 0; + ali1429_reset(); + + keyboard_at_reset(); + +// output=3; + + if ((cdrom_drive == -1) || (cdrom_drive == 0)) + cdrom_null_reset(); + else + { + if (cdrom_drive == 200) + { + iso_reset(); + } + else + { + ioctl_reset(); + } + } +} + +char romsets[17][40]={"IBM PC","IBM XT","Generic Turbo XT","Euro PC","Tandy 1000","Amstrad PC1512","Sinclair PC200","Amstrad PC1640","IBM AT","AMI 286 clone","Dell System 200","Misc 286","IBM AT 386","Misc 386","386 clone","486 clone","486 clone 2"}; +char clockspeeds[3][12][16]= +{ + {"4.77MHz","8MHz","10MHz","12MHz","16MHz"}, + {"8MHz","12MHz","16MHz","20MHz","25MHz"}, + {"16MHz","20MHz","25MHz","33MHz","40MHz","50MHz","66MHz","75MHz","80MHz","100MHz","120MHz","133MHz"}, +}; +int framecountx=0; +int sndcount=0; +int oldat70hz; + +int sreadlnum,swritelnum,segareads,segawrites, scycles_lost; + +int serial_fifo_read, serial_fifo_write; + +int emu_fps = 0; + +void runpc() +{ + char s[200]; + int done=0; + + startblit(); + clockrate = models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed; + + if (is386) + { + if (cpu_use_dynarec) + exec386_dynarec(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + else + exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + } + else if (AT) + exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + else + execx86(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + + keyboard_poll_host(); + keyboard_process(); +// checkkeys(); + pollmouse(); + joystick_poll(); + endblit(); + + framecountx++; + framecount++; + if (framecountx>=100) + { + pclog("onesec\n"); + framecountx=0; + mips=(float)insc/1000000.0f; + insc=0; + flops=(float)fpucount/1000000.0f; + fpucount=0; + sreadlnum=readlnum; + swritelnum=writelnum; + segareads=egareads; + segawrites=egawrites; + scycles_lost = cycles_lost; + + cpu_recomp_blocks_latched = cpu_recomp_blocks; + cpu_recomp_ins_latched = cpu_recomp_ins; + cpu_recomp_full_ins_latched = cpu_recomp_full_ins; + cpu_new_blocks_latched = cpu_new_blocks; + cpu_recomp_flushes_latched = cpu_recomp_flushes; + cpu_recomp_evicted_latched = cpu_recomp_evicted; + cpu_recomp_reuse_latched = cpu_recomp_reuse; + cpu_recomp_removed_latched = cpu_recomp_removed; + cpu_reps_latched = cpu_reps; + cpu_notreps_latched = cpu_notreps; + + cpu_recomp_blocks = 0; + cpu_recomp_ins = 0; + cpu_recomp_full_ins = 0; + cpu_new_blocks = 0; + cpu_recomp_flushes = 0; + cpu_recomp_evicted = 0; + cpu_recomp_reuse = 0; + cpu_recomp_removed = 0; + cpu_reps = 0; + cpu_notreps = 0; + + updatestatus=1; + readlnum=writelnum=0; + egareads=egawrites=0; + cycles_lost = 0; + mmuflush=0; + intcount=0; + intcount=pitcount=0; + emu_fps = frames; + frames = 0; + } + if (win_title_update) + { + win_title_update=0; + sprintf(s, "PCem v11 [Experimental] - %i%% - %s - %s - %s", fps, model_getname(), models[model].cpu[cpu_manufacturer].cpus[cpu].name, (!mousecapture) ? "Click to capture mouse" : "Press F12-F8 or middle button to release mouse"); + set_window_title(s); + } + done++; + frame++; +} + +void fullspeed() +{ + cpuspeed2=cpuspeed; + if (!atfullspeed) + { + printf("Set fullspeed - %i %i %i\n",is386,AT,cpuspeed2); + if (AT) + setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + else + setpitclock(14318184.0); +// if (is386) setpitclock(clocks[2][cpuspeed2][0]); +// else setpitclock(clocks[AT?1:0][cpuspeed2][0]); + } + atfullspeed=1; + nvr_recalc(); +} + +void speedchanged() +{ + if (AT) + setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + else + setpitclock(14318184.0); + mem_updatecache(); + nvr_recalc(); +} + +void closepc() +{ + atapi->exit(); +// ioctl_close(); + dumppic(); +// output=7; +// setpitclock(clocks[0][0][0]); +// while (1) runpc(); + disc_close(0); + disc_close(1); + dumpregs(); + closevideo(); + device_close_all(); + midi_close(); +} + +/*int main() +{ + initpc(); + while (!key[KEY_F11]) + { + runpc(); + } + closepc(); + return 0; +} + +END_OF_MAIN();*/ + +int cga_comp=0; + +void loadconfig(char *fn) +{ + int c, d; + char s[512]; + char *p; + + if (!fn) + config_load(config_file_default); + else + config_load(fn); + + GAMEBLASTER = config_get_int(NULL, "gameblaster", 0); + GUS = config_get_int(NULL, "gus", 0); + SSI2001 = config_get_int(NULL, "ssi2001", 0); + voodoo_enabled = config_get_int(NULL, "voodoo", 0); + + //network + ethif = config_get_int(NULL, "netinterface", 1); + if (ethif >= inum) + inum = ethif + 1; + network_card_current = config_get_int(NULL, "netcard", NE2000); + + model = config_get_int(NULL, "model", 14); + + if (model >= model_count()) + model = model_count() - 1; + + romset = model_getromset(); + cpu_manufacturer = config_get_int(NULL, "cpu_manufacturer", 0); + cpu = config_get_int(NULL, "cpu", 0); + cpu_use_dynarec = config_get_int(NULL, "cpu_use_dynarec", 0); + + gfxcard = config_get_int(NULL, "gfxcard", 0); + video_speed = config_get_int(NULL, "video_speed", 3); + sound_card_current = config_get_int(NULL, "sndcard", SB2); + + p = (char *)config_get_string(NULL, "disc_a", ""); + if (p) strcpy(discfns[0], p); + else strcpy(discfns[0], ""); + + p = (char *)config_get_string(NULL, "disc_b", ""); + if (p) strcpy(discfns[1], p); + else strcpy(discfns[1], ""); + + mem_size = config_get_int(NULL, "mem_size", 4096); + if (mem_size < (models[model].is_at ? models[model].min_ram*1024 : models[model].min_ram)) + mem_size = (models[model].is_at ? models[model].min_ram*1024 : models[model].min_ram); + + cdrom_drive = config_get_int(NULL, "cdrom_drive", 0); + old_cdrom_drive = cdrom_drive; + cdrom_enabled = config_get_int(NULL, "cdrom_enabled", 0); + + cdrom_channel = config_get_int(NULL, "cdrom_channel", 2); + + p = (char *)config_get_string(NULL, "cdrom_path", ""); + if (p) strcpy(iso_path, p); + else strcpy(iso_path, ""); + + slowega = config_get_int(NULL, "slow_video", 1); + cache = config_get_int(NULL, "cache", 3); + cga_comp = config_get_int(NULL, "cga_composite", 0); + + vid_resize = config_get_int(NULL, "vid_resize", 0); + vid_api = config_get_int(NULL, "vid_api", 0); + video_fullscreen_scale = config_get_int(NULL, "video_fullscreen_scale", 0); + video_fullscreen_first = config_get_int(NULL, "video_fullscreen_first", 1); + + hdc[0].spt = config_get_int(NULL, "hdc_sectors", 0); + hdc[0].hpc = config_get_int(NULL, "hdc_heads", 0); + hdc[0].tracks = config_get_int(NULL, "hdc_cylinders", 0); + p = (char *)config_get_string(NULL, "hdc_fn", ""); + if (p) strcpy(ide_fn[0], p); + else strcpy(ide_fn[0], ""); + hdc[1].spt = config_get_int(NULL, "hdd_sectors", 0); + hdc[1].hpc = config_get_int(NULL, "hdd_heads", 0); + hdc[1].tracks = config_get_int(NULL, "hdd_cylinders", 0); + p = (char *)config_get_string(NULL, "hdd_fn", ""); + if (p) strcpy(ide_fn[1], p); + else strcpy(ide_fn[1], ""); + hdc[2].spt = config_get_int(NULL, "hde_sectors", 0); + hdc[2].hpc = config_get_int(NULL, "hde_heads", 0); + hdc[2].tracks = config_get_int(NULL, "hde_cylinders", 0); + p = (char *)config_get_string(NULL, "hde_fn", ""); + if (p) strcpy(ide_fn[2], p); + else strcpy(ide_fn[2], ""); + hdc[3].spt = config_get_int(NULL, "hdf_sectors", 0); + hdc[3].hpc = config_get_int(NULL, "hdf_heads", 0); + hdc[3].tracks = config_get_int(NULL, "hdf_cylinders", 0); + p = (char *)config_get_string(NULL, "hdf_fn", ""); + if (p) strcpy(ide_fn[3], p); + else strcpy(ide_fn[3], ""); + + fdd_set_type(0, config_get_int(NULL, "drive_a_type", 7)); + fdd_set_type(1, config_get_int(NULL, "drive_b_type", 7)); + + force_43 = config_get_int(NULL, "force_43", 0); + enable_overscan = config_get_int(NULL, "enable_overscan", 0); + cga_color_burst = config_get_int(NULL, "cga_color_burst", 1); + cga_brown = config_get_int(NULL, "cga_brown", 1); + enable_flash = config_get_int(NULL, "enable_flash", 1); + + enable_sync = config_get_int(NULL, "enable_sync", 0); + mouse_always_serial = config_get_int(NULL, "mouse_always_serial", 0); + + window_w = config_get_int(NULL, "window_w", 0); + window_h = config_get_int(NULL, "window_h", 0); + window_x = config_get_int(NULL, "window_x", 0); + window_y = config_get_int(NULL, "window_y", 0); + window_remember = config_get_int(NULL, "window_remember", 0); + + joystick_type = config_get_int(NULL, "joystick_type", 0); + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + sprintf(s, "joystick_%i_nr", c); + joystick_state[c].plat_joystick_nr = config_get_int("Joysticks", s, 0); + + if (joystick_state[c].plat_joystick_nr) + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_axis_%i", c, d); + joystick_state[c].axis_mapping[d] = config_get_int("Joysticks", s, d); + } + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_button_%i", c, d); + joystick_state[c].button_mapping[d] = config_get_int("Joysticks", s, d); + } + } + } +} + +void saveconfig() +{ + int c, d; + + config_set_int(NULL, "gameblaster", GAMEBLASTER); + config_set_int(NULL, "gus", GUS); + config_set_int(NULL, "ssi2001", SSI2001); + config_set_int(NULL, "voodoo", voodoo_enabled); + + config_set_int(NULL, "netinterface", ethif); + config_set_int(NULL, "netcard", network_card_current); + + config_set_int(NULL, "model", model); + config_set_int(NULL, "cpu_manufacturer", cpu_manufacturer); + config_set_int(NULL, "cpu", cpu); + config_set_int(NULL, "cpu_use_dynarec", cpu_use_dynarec); + + config_set_int(NULL, "gfxcard", gfxcard); + config_set_int(NULL, "video_speed", video_speed); + config_set_int(NULL, "sndcard", sound_card_current); + config_set_int(NULL, "cpu_speed", cpuspeed); + config_set_int(NULL, "has_fpu", hasfpu); + config_set_int(NULL, "slow_video", slowega); + config_set_int(NULL, "cache", cache); + config_set_int(NULL, "cga_composite", cga_comp); + config_set_string(NULL, "disc_a", discfns[0]); + config_set_string(NULL, "disc_b", discfns[1]); + config_set_int(NULL, "mem_size", mem_size); + config_set_int(NULL, "cdrom_drive", cdrom_drive); + config_set_int(NULL, "cdrom_enabled", cdrom_enabled); + config_set_int(NULL, "cdrom_channel", cdrom_channel); + config_set_string(NULL, "cdrom_path", iso_path); + config_set_int(NULL, "vid_resize", vid_resize); + config_set_int(NULL, "vid_api", vid_api); + config_set_int(NULL, "video_fullscreen_scale", video_fullscreen_scale); + config_set_int(NULL, "video_fullscreen_first", video_fullscreen_first); + + config_set_int(NULL, "hdc_sectors", hdc[0].spt); + config_set_int(NULL, "hdc_heads", hdc[0].hpc); + config_set_int(NULL, "hdc_cylinders", hdc[0].tracks); + config_set_string(NULL, "hdc_fn", ide_fn[0]); + config_set_int(NULL, "hdd_sectors", hdc[1].spt); + config_set_int(NULL, "hdd_heads", hdc[1].hpc); + config_set_int(NULL, "hdd_cylinders", hdc[1].tracks); + config_set_string(NULL, "hdd_fn", ide_fn[1]); + config_set_int(NULL, "hde_sectors", hdc[2].spt); + config_set_int(NULL, "hde_heads", hdc[2].hpc); + config_set_int(NULL, "hde_cylinders", hdc[2].tracks); + config_set_string(NULL, "hde_fn", ide_fn[2]); + config_set_int(NULL, "hdf_sectors", hdc[3].spt); + config_set_int(NULL, "hdf_heads", hdc[3].hpc); + config_set_int(NULL, "hdf_cylinders", hdc[3].tracks); + config_set_string(NULL, "hdf_fn", ide_fn[3]); + + config_set_int(NULL, "drive_a_type", fdd_get_type(0)); + config_set_int(NULL, "drive_b_type", fdd_get_type(1)); + + config_set_int(NULL, "force_43", force_43); + config_set_int(NULL, "enable_overscan", enable_overscan); + config_set_int(NULL, "cga_color_burst", cga_color_burst); + config_set_int(NULL, "cga_brown", cga_brown); + config_set_int(NULL, "enable_flash", enable_flash); + + config_set_int(NULL, "enable_sync", enable_sync); + config_set_int(NULL, "mouse_always_serial", mouse_always_serial); + + config_set_int(NULL, "joystick_type", joystick_type); + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + char s[80]; + + sprintf(s, "joystick_%i_nr", c); + config_set_int("Joysticks", s, joystick_state[c].plat_joystick_nr); + + if (joystick_state[c].plat_joystick_nr) + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_axis_%i", c, d); + config_set_int("Joysticks", s, joystick_state[c].axis_mapping[d]); + } + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_button_%i", c, d); + config_set_int("Joysticks", s, joystick_state[c].button_mapping[d]); + } + } + } + + config_set_int(NULL, "window_w", window_w); + config_set_int(NULL, "window_h", window_h); + config_set_int(NULL, "window_x", window_x); + config_set_int(NULL, "window_y", window_y); + config_set_int(NULL, "window_remember", window_remember); + + config_save(config_file_default); +} diff --git a/src/pc.rc b/src/pc.rc new file mode 100644 index 000000000..a820d6f35 --- /dev/null +++ b/src/pc.rc @@ -0,0 +1,252 @@ +#include +#include "resources.h" + +#ifndef UPDOWN_CLASS +#define UPDOWN_CLASS L"msctls_updown32" +#endif + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Hard Reset", IDM_FILE_HRESET + MENUITEM "&Ctrl+Alt+Del", IDM_FILE_RESET_CAD + MENUITEM "E&xit", IDM_FILE_EXIT + END + POPUP "&Disc" + BEGIN + MENUITEM "Change drive &A:...", IDM_DISC_A + MENUITEM "Change drive &B:...", IDM_DISC_B + MENUITEM "&Eject drive A:", IDM_EJECT_A + MENUITEM "Eject drive B:", IDM_EJECT_B + MENUITEM "&Configure hard discs...",IDM_HDCONF + END + POPUP "&Settings" + BEGIN + MENUITEM "&Configure...", IDM_CONFIG + POPUP "&CD-ROM" + BEGIN + MENUITEM "&Disabled", IDM_CDROM_DISABLED + MENUITEM "&Empty",IDM_CDROM_EMPTY + MENUITEM "&ISO...",IDM_CDROM_ISO + END + POPUP "&Video" + BEGIN + MENUITEM "&Resizeable window",IDM_VID_RESIZE + MENUITEM "Remember size && position",IDM_VID_REMEMBER + MENUITEM SEPARATOR + MENUITEM "&DirectDraw", IDM_VID_DDRAW + MENUITEM "Direct&3D", IDM_VID_D3D + MENUITEM SEPARATOR + MENUITEM "&Fullscreen", IDM_VID_FULLSCREEN + POPUP "Fullscreen &stretch mode" + BEGIN + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels", IDM_VID_FS_SQ + MENUITEM "&Integer scale", IDM_VID_FS_INT + END + END + MENUITEM SEPARATOR + MENUITEM "&Load configuration...", IDM_CONFIG_LOAD + MENUITEM "&Save configuration...", IDM_CONFIG_SAVE + END + POPUP "&Misc" + BEGIN + MENUITEM "&Status", IDM_STATUS + END +END + +ConfigureDlg DIALOGEX 0, 0, 248+40, 248+76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configure PCem" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,64,300,50,14, WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,128,300,50,14, WS_TABSTOP + COMBOBOX IDC_COMBO1,62,16,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOVID,62,36,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure", IDC_CONFIGUREVID, 224, 36, 40, 14, WS_TABSTOP + COMBOBOX IDC_COMBOCPUM,62,56,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO3,62,76,102,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + CONTROL "Dynamic Recompiler",IDC_CHECKDYNAREC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,169,76,99,10 + COMBOBOX IDC_COMBOCHC,62,96,57,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOSPD,162,96,57,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOSND,62,116,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure", IDC_CONFIGURESND, 224, 116, 40, 14, WS_TABSTOP + EDITTEXT IDC_MEMTEXT, 62, 136, 36, 14, ES_AUTOHSCROLL | ES_NUMBER + CONTROL "", IDC_MEMSPIN, UPDOWN_CLASS, UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_SETBUDDYINT, 98, 136, 12, 14 + LTEXT "MB", IDC_TEXT_MB, 98, 136, 10, 10 + CONTROL "CMS / Game Blaster",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,172,102,10 + CONTROL "Gravis Ultrasound",IDC_CHECKGUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,188,102,10 + CONTROL "Innovation SSI-2001",IDC_CHECKSSI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,204,102,10 + CONTROL "Composite CGA",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,220,102,10 + CONTROL "Enable time sync",IDC_CHECKSYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,236,102,10 + + CONTROL "Force 4:3 display ratio",IDC_CHECKFORCE43,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,172,102,10 + CONTROL "Composite CGA color burst",IDC_CHECKCBURST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,188,102,10 + CONTROL "RGB CGA brown circuit",IDC_CHECKBROWN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,204,102,10 + CONTROL "EGA/(S)VGA overscan",IDC_CHECKOVERSCAN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,220,102,10 + CONTROL "Disk activity flash",IDC_CHECKFLASH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,236,102,10 + + CONTROL "Ser. mouse instead of PS/2",IDC_CHECKSERIAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,252,102,10 + + CONTROL "Voodoo Graphics",IDC_CHECKVOODOO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,252,102,10 + PUSHBUTTON "Configure", IDC_CONFIGUREVOODOO, 224, 252, 40, 14, WS_TABSTOP + + LTEXT "Joystick :",IDC_STATIC,15,268,40,10 + COMBOBOX IDC_COMBOJOY,62,268,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "Joystick 1...",IDC_JOY1,16,284,50,14, WS_TABSTOP + PUSHBUTTON "Joystick 2...",IDC_JOY2,80,284,50,14, WS_TABSTOP + DEFPUSHBUTTON "Joystick 3...",IDC_JOY3,144,284,50,14, WS_TABSTOP + PUSHBUTTON "Joystick 4...",IDC_JOY4,208,284,50,14, WS_TABSTOP + + LTEXT "Machine :",IDC_STATIC,15,16,40,10 + LTEXT "Video :",IDC_STATIC,15,36,34,10 + LTEXT "CPU type :",IDC_STATIC,15,56,34,10 + LTEXT "CPU :",IDC_STATIC,15,76,34,10 + LTEXT "Cache :",IDC_STATIC,15,96,40,10 + LTEXT "Vid. speed :",IDC_STATIC,125,96,34,10 + LTEXT "Soundcard :",IDC_STATIC,15,116,40,10 + LTEXT "Network :",IDC_STATIC,125,136,34,10 + COMBOBOX IDC_COMBONET,162,136,57,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure", IDC_CONFIGURENET, 224, 136, 40, 14, WS_TABSTOP + LTEXT "Memory :",IDC_STATIC,15,136,40,10 + LTEXT "Drive A: :",IDC_STATIC,15,156,40,10 + LTEXT "Drive B: :",IDC_STATIC,125,156,40,10 + COMBOBOX IDC_COMBODRA,62,156,57,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBODRB,162,156,57,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP +END + +HdConfDlg DIALOGEX 0, 0, 210, 310+4*16 + STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU + CAPTION "Configure Hard Discs" + FONT 8, "MS Sans Serif" + BEGIN + DEFPUSHBUTTON "OK",IDOK,31+12,290+64,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101+12,290+64,50,14 + + LTEXT "C:",IDC_STATIC,7,6,27,10 + RADIOBUTTON "Hard drive", IDC_CHDD, 7+64, 6, 53, 12 , WS_TABSTOP + RADIOBUTTON "CD-ROM", IDC_CCDROM, 7+128, 6, 53, 12 , WS_TABSTOP + EDITTEXT IDC_EDIT_C_FN, 7, 6+16, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_CFILE,7 + 136, 6+16, 16, 14 + PUSHBUTTON "New",IDC_CNEW,7 + 136 + 16, 6+16, 24, 14 + PUSHBUTTON "Eject", IDC_EJECTC, 7 + 136 + 16 + 24, 6+16, 24, 14 + + EDITTEXT IDC_EDIT_C_SPT,36,22+16,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_C_HPC,94,22+16,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_C_CYL,152,22+16,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,22+16,27,10 + LTEXT "Heads:",IDC_STATIC,63,22+16,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,22+16,32,12 + LTEXT "", IDC_TEXT_C_SIZE, 7, 38+16, 136, 12 + + LTEXT "D:",IDC_STATIC,7,60+16,27,10 + RADIOBUTTON "Hard drive", IDC_DHDD, 7+64, 60+16, 53, 12 , WS_TABSTOP + RADIOBUTTON "CD-ROM", IDC_DCDROM, 7+128, 60+16, 53, 12 , WS_TABSTOP + EDITTEXT IDC_EDIT_D_FN, 7, 60+32, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_DFILE,7 + 136, 60+32, 16, 14 + PUSHBUTTON "New",IDC_DNEW,7 + 136 + 16, 60+32, 24, 14 + PUSHBUTTON "Eject", IDC_EJECTD, 7 + 136 + 16 + 24, 60+32, 24, 14 + + EDITTEXT IDC_EDIT_D_SPT,36,76+32,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_D_HPC,94,76+32,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_D_CYL,152,76+32,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,76+32,27,10 + LTEXT "Heads:",IDC_STATIC,63,76+32,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,76+32,32,12 + LTEXT "", IDC_TEXT_D_SIZE, 7, 92+32, 136, 12 + + LTEXT "E:",IDC_STATIC,7,114+32,27,10 + RADIOBUTTON "Hard drive", IDC_EHDD, 7+64, 114+32, 53, 12 , WS_TABSTOP + RADIOBUTTON "CD-ROM", IDC_ECDROM, 7+128, 114+32, 53, 12 , WS_TABSTOP + EDITTEXT IDC_EDIT_E_FN, 7, 114+48, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_EFILE,7 + 136, 114+48, 16, 14 + PUSHBUTTON "New",IDC_ENEW,7 + 136 + 16, 114+48, 24, 14 + PUSHBUTTON "Eject", IDC_EJECTE, 7 + 136 + 16 + 24, 114+48, 24, 14 + + EDITTEXT IDC_EDIT_E_SPT,36,130+48,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_E_HPC,94,130+48,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_E_CYL,152,130+48,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,130+48,27,10 + LTEXT "Heads:",IDC_STATIC,63,130+48,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,130+48,32,12 + LTEXT "", IDC_TEXT_E_SIZE, 7, 146+48, 136, 12 + + LTEXT "F:",IDC_STATIC,7,168+48,27,10 + RADIOBUTTON "Hard drive", IDC_FHDD, 7+64, 168+48, 53, 12 , WS_TABSTOP + RADIOBUTTON "CD-ROM", IDC_FCDROM, 7+128, 168+48, 53, 12 , WS_TABSTOP + EDITTEXT IDC_EDIT_F_FN, 7, 168+64, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_FFILE,7 + 136, 168+64, 16, 14 + PUSHBUTTON "New",IDC_FNEW,7 + 136 + 16, 168+64, 24, 14 + PUSHBUTTON "Eject", IDC_EJECTF, 7 + 136 + 16 + 24, 168+64, 24, 14 + + EDITTEXT IDC_EDIT_F_SPT,36,184+64,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_F_HPC,94,184+64,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_F_CYL,152,184+64,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,184+64,27,10 + LTEXT "Heads:",IDC_STATIC,63,184+64,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,184+64,32,12 + LTEXT "", IDC_TEXT_F_SIZE, 7, 200+64, 136, 12 + + LTEXT "G:",IDC_STATIC,7,222+64,27,10 + RADIOBUTTON "CD-ROM", IDC_GCDROM, 7+128, 222+64, 53, 12 , WS_TABSTOP + + LTEXT "H:",IDC_STATIC,7,262+64,27,10 + RADIOBUTTON "CD-ROM", IDC_HCDROM, 7+128, 262+64, 53, 12 , WS_TABSTOP + +END + +HdNewDlg DIALOGEX 0, 0, 186, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "New Hard Disc" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,31,66,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14 + + EDITTEXT IDC_EDITC, 7, 6, 136, 12 + PUSHBUTTON "...",IDC_CFILE,7 + 136, 6, 16, 14 + + EDITTEXT IDC_EDIT1,36,22,16,12 + EDITTEXT IDC_EDIT2,94,22,16,12 + EDITTEXT IDC_EDIT3,152,22,28,12 + LTEXT "Sectors:",IDC_STATIC,7,22,27,10 + LTEXT "Heads:",IDC_STATIC,63,22,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,22,32,12 + LTEXT "", IDC_TEXT1, 7, 38, 136, 12 +END + +HdSizeDlg DIALOGEX 0, 0, 186, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Hard disc parameters" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,31,66,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14 + + LTEXT "Initial settings are based on file size",IDC_STATIC,7,6,170,10 + + EDITTEXT IDC_EDIT1,36,22,16,12 + EDITTEXT IDC_EDIT2,94,22,16,12 + EDITTEXT IDC_EDIT3,152,22,28,12 + LTEXT "Sectors:",IDC_STATIC,7,22,27,10 + LTEXT "Heads:",IDC_STATIC,63,22,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,22,32,12 + LTEXT "", IDC_TEXT1, 7, 38, 136, 12 +END + +StatusDlg DIALOGEX 0,0,186,186+20+180 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Status" +FONT 9, "Segoe UI" +BEGIN + LTEXT "1",IDC_STEXT_DEVICE,16,16,180,1000 + LTEXT "1",IDC_STEXT1,16,186,180,1000 +END + +1 24 "PCem.manifest" + +/* Icon by PixelOz - http://pixeloz.deviantart.com/art/Computer-Emulator-Icons-135675096 */ +100 ICON "IBMPCAT-1.ico" diff --git a/src/pc87306.c b/src/pc87306.c new file mode 100644 index 000000000..f7b0023fd --- /dev/null +++ b/src/pc87306.c @@ -0,0 +1,295 @@ +/* + National Semiconductors PC87306 Super I/O Chip + Used by Intel Advanced/EV +*/ + +#include "ibm.h" + +#include "fdc.h" +#include "fdd.h" +#include "io.h" +#include "lpt.h" +#include "mouse_serial.h" +#include "serial.h" +#include "pc87306.h" + +static int pc87306_locked; +static int pc87306_curreg; +static uint8_t pc87306_regs[29]; +static uint8_t pc87306_gpio[2] = {0xFF, 0xFF}; +static uint8_t tries; +static uint16_t lpt_port; + +void pc87306_gpio_remove(); +void pc87306_gpio_init(); + +void pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + pc87306_gpio[port & 1] = val; +} + +uint8_t uart_int1() +{ + return ((pc87306_regs[0x1C] >> 2) & 1) ? 3 : 4; +} + +uint8_t uart_int2() +{ + return ((pc87306_regs[0x1C] >> 6) & 1) ? 3 : 4; +} + +uint8_t uart1_int() +{ + return (pc87306_regs[0x1C] & 1) ? uart_int1() : 4; +} + +uint8_t uart2_int() +{ + return (pc87306_regs[0x1C] & 1) ? uart_int2() : 3; +} + +void serial1_handler() +{ + int temp; + temp = (pc87306_regs[1] >> 2) & 3; + switch (temp) + { + case 0: serial1_set(0x3f8, uart1_int()); break; + case 1: serial1_set(0x2f8, uart1_int()); break; + case 2: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial1_set(0x3e8, uart1_int()); break; + case 1: serial1_set(0x338, uart1_int()); break; + case 2: serial1_set(0x2e8, uart1_int()); break; + case 3: serial1_set(0x220, uart1_int()); break; + } + break; + case 3: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial1_set(0x2e8, uart1_int()); break; + case 1: serial1_set(0x238, uart1_int()); break; + case 2: serial1_set(0x2e0, uart1_int()); break; + case 3: serial1_set(0x228, uart1_int()); break; + } + break; + } +} + +void serial2_handler() +{ + int temp; + temp = (pc87306_regs[1] >> 4) & 3; + switch (temp) + { + case 0: serial2_set(0x3f8, uart2_int()); break; + case 1: serial2_set(0x2f8, uart2_int()); break; + case 2: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial2_set(0x3e8, uart2_int()); break; + case 1: serial2_set(0x338, uart2_int()); break; + case 2: serial2_set(0x2e8, uart2_int()); break; + case 3: serial2_set(0x220, uart2_int()); break; + } + break; + case 3: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial2_set(0x2e8, uart2_int()); break; + case 1: serial2_set(0x238, uart2_int()); break; + case 2: serial2_set(0x2e0, uart2_int()); break; + case 3: serial2_set(0x228, uart2_int()); break; + } + break; + } +} + +void pc87306_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + int temp; + uint8_t valxor; + // pclog("pc87306_write : port=%04x reg %02X = %02X locked=%i\n", port, pc87306_curreg, val, pc87306_locked); + + if (index) + { + pc87306_curreg = val; + tries = 0; + return; + } + else + { + if (tries) + { + if (pc87306_curreg <= 28) valxor = val ^ pc87306_regs[pc87306_curreg]; + if (pc87306_curreg == 0xF) pc87306_gpio_remove(); + if (pc87306_curreg <= 28) pc87306_regs[pc87306_curreg] = val; + tries = 0; + if (pc87306_curreg <= 28) goto process_value; + } + else + { + tries++; + return; + } + } + +process_value: + switch(pc87306_curreg) + { + case 0: + if (valxor & 1) + { + lpt1_remove(); + lpt2_remove(); + } + if ((valxor & 1) && (val & 1)) + { + if (pc87306_regs[0x1B] & 0x10) + { + temp = (pc87306_regs[0x1B] & 0x20) >> 5; + if (temp) + { + lpt1_init(0x378); break; + } + else + { + lpt1_init(0x278); break; + } + } + else + { + temp = pc87306_regs[1] & 3; + switch (temp) + { + case 0: lpt1_init(0x378); break; + case 1: lpt1_init(0x3bc); break; + case 2: lpt1_init(0x278); break; + } + } + } + serial1_remove(); + serial2_remove(); + if (val & 2) + { + serial1_handler(); + // mouse_serial_init(); + } + if (val & 4) serial2_handler(); + + break; + case 1: + lpt1_remove(); + if (pc87306_regs[0] & 1) + { + if (pc87306_regs[0x1B] & 0x10) + { + temp = (pc87306_regs[0x1B] & 0x20) >> 5; + if (temp) + { + lpt_port = 0x378; break; + } + else + { + lpt_port = 0x278; break; + } + } + else + { + temp = val & 3; + switch (temp) + { + case 0: lpt_port = 0x378; break; + case 1: lpt_port = 0x3bc; break; + case 2: lpt_port = 0x278; break; + } + } + lpt1_init(lpt_port); + pc87306_regs[0x19] = lpt_port >> 2; + } + serial1_remove(); + serial2_remove(); + + if (pc87306_regs[0] & 2) + { + serial1_handler(); + // mouse_serial_init(); + } + if (pc87306_regs[0] & 4) serial2_handler(); + break; + case 9: + // pclog("Setting DENSEL polarity to: %i (before: %i)\n", (val & 0x40 ? 1 : 0), fdc_get_densel_polarity()); + fdc_update_densel_polarity(val & 0x40 ? 1 : 0); + break; + case 0xF: + pc87306_gpio_init(); + break; + case 0x1C: + if (valxor & 1) + { + serial1_remove(); + serial2_remove(); + if (pc87306_regs[0] & 2) + { + serial1_handler(); + // mouse_serial_init(); + } + if (pc87306_regs[0] & 4) serial2_handler(); + } + break; + } +} + +uint8_t pc87306_gpio_read(uint16_t port, void *priv) +{ + return pc87306_gpio[port & 1]; +} + +uint8_t pc87306_read(uint16_t port, void *priv) +{ + // pclog("pc87306_read : port=%04x reg %02X locked=%i\n", port, pc87306_curreg, pc87306_locked); + uint8_t index = (port & 1) ? 0 : 1; + + if (index) + return pc87306_curreg; + else + { + if (pc87306_curreg >= 28) + return 0xff; + else + return pc87306_regs[pc87306_curreg]; + } +} + +void pc87306_gpio_remove() +{ + io_removehandler(pc87306_regs[0xF] << 2, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); +} + +void pc87306_gpio_init() +{ + io_sethandler(pc87306_regs[0xF] << 2, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); +} + +void pc87306_init() +{ + pc87306_regs[0] = 0xF; + pc87306_regs[1] = 0x11; + pc87306_regs[5] = 0xD; + pc87306_regs[8] = 0x70; + pc87306_regs[9] = 0xFF; + pc87306_regs[0xF] = 0x1E; + pc87306_regs[0x19] = 0xDE; + pc87306_regs[0x1B] = 0x10; + pc87306_regs[0x1C] = 0; + /* + 0 = 360 rpm @ 500 kbps for 3.5" + 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" + */ + fdc_update_is_nsc(1); + fdc_update_densel_polarity(1); + fdd_swap = 0; + io_sethandler(0x02e, 0x0002, pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, NULL); +} diff --git a/src/pc87306.h b/src/pc87306.h new file mode 100644 index 000000000..61a926722 --- /dev/null +++ b/src/pc87306.h @@ -0,0 +1 @@ +extern void pc87306_init(); diff --git a/src/pci.c b/src/pci.c new file mode 100644 index 000000000..ebffaa007 --- /dev/null +++ b/src/pci.c @@ -0,0 +1,166 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" + +#include "pci.h" + +void (*pci_card_write[32])(int func, int addr, uint8_t val, void *priv); +uint8_t (*pci_card_read[32])(int func, int addr, void *priv); +void *pci_priv[32]; +static int pci_index, pci_func, pci_card, pci_bus, pci_enable, pci_key; +static int pci_min_card, pci_max_card; +int pci_burst_time, pci_nonburst_time; + +void pci_cf8_write(uint16_t port, uint32_t val, void *p) +{ + pci_index = val & 0xff; + pci_func = (val >> 8) & 7; + pci_card = (val >> 11) & 31; + pci_bus = (val >> 16) & 0xff; + pci_enable = (val >> 31) & 1; + // pclog("PCI card selected: %i\n", pci_card); +} + +uint32_t pci_cf8_read(uint16_t port, void *p) +{ + return pci_index | (pci_func << 8) | (pci_card << 11) | (pci_bus << 16) | (pci_enable << 31); +} + +void pci_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("pci_write: port=%04x val=%02x %08x:%08x\n", port, val, cs, pc); + switch (port) + { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (!pci_enable) + return; + +// pclog("PCI write bus %i card %i func %i index %02X val %02X %04X:%04X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3), val, CS, pc); + + if (!pci_bus && pci_card_write[pci_card]) + pci_card_write[pci_card](pci_func, pci_index | (port & 3), val, pci_priv[pci_card]); + + break; + } +} + +uint8_t pci_read(uint16_t port, void *priv) +{ +// pclog("pci_read: port=%04x %08x:%08x\n", port, cs, pc); + switch (port) + { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (!pci_enable) + return 0xff; + +// pclog("PCI read bus %i card %i func %i index %02X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3)); + + if (!pci_bus && pci_card_read[pci_card]) + return pci_card_read[pci_card](pci_func, pci_index | (port & 3), pci_priv[pci_card]); + + return 0xff; + } +} + +void pci_type2_write(uint16_t port, uint8_t val, void *priv); +uint8_t pci_type2_read(uint16_t port, void *priv); + +void pci_type2_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("pci_type2_write: port=%04x val=%02x %08x:%08x\n", port, val, cs, pc); + if (port == 0xcf8) + { + pci_func = (val >> 1) & 7; + if (!pci_key && (val & 0xf0)) + io_sethandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + else + io_removehandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + pci_key = val & 0xf0; + } + else if (port == 0xcfa) + { + pci_bus = val; + } + else + { + pci_card = (port >> 8) & 0xf; + pci_index = port & 0xff; + +// pclog("PCI write bus %i card %i func %i index %02X val %02X %04X:%04X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3), val, CS, pc); + + if (!pci_bus && pci_card_write[pci_card]) + pci_card_write[pci_card](pci_func, pci_index | (port & 3), val, pci_priv[pci_card]); + } +} + +uint8_t pci_type2_read(uint16_t port, void *priv) +{ +// pclog("pci_type2_read: port=%04x %08x:%08x\n", port, cs, pc); + if (port == 0xcf8) + { + return pci_key | (pci_func << 1); + } + else if (port == 0xcfa) + { + return pci_bus; + } + else + { + pci_card = (port >> 8) & 0xf; + pci_index = port & 0xff; + +// pclog("PCI read bus %i card %i func %i index %02X %04X:%04X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3), CS, pc); + + if (!pci_bus && pci_card_write[pci_card]) + return pci_card_read[pci_card](pci_func, pci_index | (port & 3), pci_priv[pci_card]); + } + return 0xff; +} + +void pci_init(int type, int min_card, int max_card) +{ + int c; + + PCI = 1; + + if (type == PCI_CONFIG_TYPE_1) + { + io_sethandler(0x0cf8, 0x0001, NULL, NULL, pci_cf8_read, NULL, NULL, pci_cf8_write, NULL); + io_sethandler(0x0cfc, 0x0004, pci_read, NULL, NULL, pci_write, NULL, NULL, NULL); + } + else + { + io_sethandler(0x0cf8, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + io_sethandler(0x0cfa, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + } + + for (c = 0; c < 32; c++) + pci_card_read[c] = pci_card_write[c] = pci_priv[c] = NULL; + + pci_min_card = min_card; + pci_max_card = max_card; +} + +void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) +{ + pci_card_read[card] = read; + pci_card_write[card] = write; + pci_priv[card] = priv; +} + +void pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) +{ + int c; + + for (c = pci_min_card; c <= pci_max_card; c++) + { + if (!pci_card_read[c] && !pci_card_write[c]) + { + pci_card_read[c] = read; + pci_card_write[c] = write; + pci_priv[c] = priv; + // pclog("PCI device added to card: %i\n", c); + return; + } + } +} diff --git a/src/pci.h b/src/pci.h new file mode 100644 index 000000000..8fcbd1893 --- /dev/null +++ b/src/pci.h @@ -0,0 +1,13 @@ +void pci_init(int type, int min_card, int max_card); +void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); +void pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); + +#define PCI_REG_COMMAND 0x04 + +#define PCI_COMMAND_IO 0x01 +#define PCI_COMMAND_MEM 0x02 + +#define PCI_CONFIG_TYPE_1 1 +#define PCI_CONFIG_TYPE_2 2 + +extern int pci_burst_time, pci_nonburst_time; diff --git a/src/pic.c b/src/pic.c new file mode 100644 index 000000000..e3549f71c --- /dev/null +++ b/src/pic.c @@ -0,0 +1,423 @@ +#include "ibm.h" +#include "io.h" +#include "pic.h" + +int output; +int intclear; +int keywaiting=0; +int pic_intpending; + +void pic_updatepending() +{ + if ((pic2.pend&~pic2.mask)&~pic2.mask2) + pic.pend |= (1 << 2); + else + pic.pend &= ~(1 << 2); + pic_intpending = (pic.pend & ~pic.mask) & ~pic.mask2; + if (!((pic.mask | pic.mask2) & (1 << 2))) + pic_intpending |= ((pic2.pend&~pic2.mask)&~pic2.mask2); +/* pclog("pic_intpending = %i %02X %02X %02X %02X\n", pic_intpending, pic.ins, pic.pend, pic.mask, pic.mask2); + pclog(" %02X %02X %02X %02X %i %i\n", pic2.ins, pic2.pend, pic2.mask, pic2.mask2, ((pic.mask | pic.mask2) & (1 << 2)), ((pic2.pend&~pic2.mask)&~pic2.mask2));*/ +} + + +void pic_reset() +{ + pic.icw=0; + pic.mask=0xFF; + pic.mask2=0; + pic.pend=pic.ins=0; + pic.vector=8; + pic.read=1; + pic2.icw=0; + pic2.mask=0xFF; + pic.mask2=0; + pic2.pend=pic2.ins=0; + pic_intpending = 0; +} + +void pic_update_mask(uint8_t *mask, uint8_t ins) +{ + int c; + *mask = 0; + for (c = 0; c < 8; c++) + { + if (ins & (1 << c)) + { + *mask = 0xff << c; + return; + } + } +} + +static void pic_autoeoi() +{ + int c; + + for (c=0;c<8;c++) + { + if (pic.ins&(1<0xFF) + { + pic2.pend|=(num>>8); + if ((pic2.pend&~pic2.mask)&~pic2.mask2) + pic.pend |= (1 << 2); + } + else + { + pic.pend|=num; + } +// pclog("picint : PEND now %02X %02X\n", pic.pend, pic2.pend); + pic_updatepending(); +} + +void picintlevel(uint16_t num) +{ + int c = 0; + while (!(num & (1 << c))) c++; + if (AT && c == 2) + { + c = 9; + num = 1 << 9; + } +// pclog("INTLEVEL %04X %i\n", num, c); + if (!pic_current[c]) + { + pic_current[c]=1; + if (num>0xFF) + { + pic2.pend|=(num>>8); + } + else + { + pic.pend|=num; + } + } + pic_updatepending(); +} +void picintc(uint16_t num) +{ + int c = 0; + if (!num) + return; + while (!(num & (1 << c))) c++; + if (AT && c == 2) + { + c = 9; + num = 1 << 9; + } +// pclog("INTC %04X %i\n", num, c); + pic_current[c]=0; + + if (num > 0xff) + { + pic2.pend &= ~(num >> 8); + if (!((pic2.pend&~pic2.mask)&~pic2.mask2)) + pic.pend &= ~(1 << 2); + } + else + { + pic.pend&=~num; + } + pic_updatepending(); +} + +uint8_t picinterrupt() +{ + uint8_t temp=pic.pend&~pic.mask; + int c; + for (c = 0; c < 2; c++) + { + if (temp & (1 << c)) + { + pic.pend &= ~(1 << c); + pic.ins |= (1 << c); + pic_update_mask(&pic.mask2, pic.ins); + pic_updatepending(); + + if (pic.icw4 & 0x02) + pic_autoeoi(); + + return c+pic.vector; + } + } + if (temp & (1 << 2)) + { + uint8_t temp2 = pic2.pend & ~pic2.mask; + for (c = 0; c < 8; c++) + { + if (temp2 & (1 << c)) + { + pic2.pend &= ~(1 << c); + pic2.ins |= (1 << c); + pic_update_mask(&pic2.mask2, pic2.ins); + + pic.pend &= ~(1 << c); + pic.ins |= (1 << 2); /*Cascade IRQ*/ + pic_update_mask(&pic.mask2, pic.ins); + + pic_updatepending(); + + if (pic2.icw4 & 0x02) + pic2_autoeoi(); + + return c+pic2.vector; + } + } + } + for (c = 3; c < 8; c++) + { + if (temp & (1 << c)) + { + pic.pend &= ~(1 << c); + pic.ins |= (1 << c); + pic_update_mask(&pic.mask2, pic.ins); + pic_updatepending(); + + if (pic.icw4 & 0x02) + pic_autoeoi(); + + return c+pic.vector; + } + } + return 0xFF; +} + +void dumppic() +{ + pclog("PIC1 : MASK %02X PEND %02X INS %02X VECTOR %02X\n",pic.mask,pic.pend,pic.ins,pic.vector); + pclog("PIC2 : MASK %02X PEND %02X INS %02X VECTOR %02X\n",pic2.mask,pic2.pend,pic2.ins,pic2.vector); +} + diff --git a/src/pic.h b/src/pic.h new file mode 100644 index 000000000..419315c5f --- /dev/null +++ b/src/pic.h @@ -0,0 +1,9 @@ +void pic_init(); +void pic2_init(); +void pic_reset(); + +void picint(uint16_t num); +void picintlevel(uint16_t num); +void picintc(uint16_t num); +uint8_t picinterrupt(); +void picclear(int num); diff --git a/src/piix.c b/src/piix.c new file mode 100644 index 000000000..4f32d7202 --- /dev/null +++ b/src/piix.c @@ -0,0 +1,570 @@ +/*PRD format : + + word 0 - base address + word 1 - bits 1 - 15 = byte count, bit 31 = end of transfer +*/ +#include + +#include "ibm.h" +#include "ide.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "piix.h" + +uint8_t piix_33 = 0; + +uint8_t piix_bus_master_read(uint16_t port, void *priv); +void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); + +static uint8_t piix_type = 1; +static uint8_t card_piix[256], card_piix_ide[256]; + +void piix_write(int func, int addr, uint8_t val, void *priv) +{ +// pclog("piix_write: func=%d addr=%02x val=%02x %04x:%08x\n", func, addr, val, CS, pc); + if (func > 1) + return; + + if (func == 1) /*IDE*/ + { + switch (addr) + { + case 0x04: + if (val & 0x10) resetide(); /* Only the ASUS boards attempt to modify this register - reset IDE when that happens. Fixes soft reset on the ASUS boards. */ + card_piix_ide[0x04] = (card_piix_ide[0x04] & ~5) | (val & 5); + break; + case 0x07: + card_piix_ide[0x07] = (card_piix_ide[0x07] & ~0x38) | (val & 0x38); + break; + case 0x0d: + card_piix_ide[0x0d] = val; + break; + + case 0x20: + card_piix_ide[0x20] = (val & ~0x0f) | 1; + break; + case 0x21: + card_piix_ide[0x21] = val; + break; + +#if 0 + case 0x33: + /* Note by OBattler: This is a hack, but it's needed to reset the cylinders of the IDE devices. */ + if (romset != ROM_P55T2P4) break; + if (val != piix_33) + { + resetide(); + } + piix_33 = val; + break; +#endif + + case 0x40: + card_piix_ide[0x40] = val; + break; + case 0x41: + if ((val ^ card_piix_ide[0x41]) & 0x80) + { + ide_pri_disable(); + if (val & 0x80) + ide_pri_enable(); + } + card_piix_ide[0x41] = val; + break; + case 0x42: + card_piix_ide[0x42] = val; + break; + case 0x43: + if ((val ^ card_piix_ide[0x43]) & 0x80) + { + ide_sec_disable(); + if (val & 0x80) + ide_sec_enable(); + } + card_piix_ide[0x43] = val; + break; + case 0x44: + if (piix_type >= 3) card_piix_ide[0x44] = val; + break; + } + if (addr == 4 || (addr & ~3) == 0x20) /*Bus master base address*/ + { + uint16_t base = (card_piix_ide[0x20] & 0xf0) | (card_piix_ide[0x21] << 8); + io_removehandler(0, 0x10000, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + if (card_piix_ide[0x04] & 1) + io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + } +// pclog("PIIX write %02X %02X\n", addr, val); + } + else + { + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + } + if (addr == 0x6A) + { + if (piix_type == 1) + card_piix[addr] = (val & 0xFC) | (card_piix[addr] | 3); + else if (piix_type == 3) + card_piix[addr] = (val & 0xFD) | (card_piix[addr] | 2); + } + else + card_piix[addr] = val; + } +} + +uint8_t piix_read(int func, int addr, void *priv) +{ +// pclog("piix_read: func=%d addr=%02x %04x:%08x\n", func, addr, CS, pc); + if (func > 1) + return 0xff; + + if (func == 1) /*IDE*/ + { +// pclog("PIIX IDE read %02X %02X\n", addr, card_piix_ide[addr]); + + if (addr == 4) + { + return (card_piix_ide[addr] & 4) | 3; + } + else if (addr == 5) + { + return 0; + } + else if (addr == 6) + { + return 0x80; + } + else if (addr == 7) + { + return card_piix_ide[addr] & 0x3E; + } + else if (addr == 0xD) + { + return card_piix_ide[addr] & 0xF0; + } + else if (addr == 0x20) + { + return card_piix_ide[addr] & 0xF1; + } + else if (addr == 0x22) + { + return 0; + } + else if (addr == 0x23) + { + return 0; + } + else if (addr == 0x41) + { + if (piix_type == 1) + return card_piix_ide[addr] & 0xB3; + else if (piix_type == 3) + return card_piix_ide[addr] & 0xF3; + } + else if (addr == 0x43) + { + if (piix_type == 1) + return card_piix_ide[addr] & 0xB3; + else if (piix_type == 3) + return card_piix_ide[addr] & 0xF3; + } + else + { + return card_piix_ide[addr]; + } + } + else + { + if ((addr & 0xFC) == 0x60) + { + return card_piix[addr] & 0x8F; + } + if (addr == 4) + { + return (card_piix[addr] & 0x80) | 7; + } + else if (addr == 5) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 1; + } + else if (addr == 6) + { + return card_piix[addr] & 0x80; + } + else if (addr == 7) + { + if (piix_type == 1) + return card_piix[addr] & 0x3E; + else if (piix_type == 3) + return card_piix[addr]; + } + else if (addr == 0x69) + { + return card_piix[addr] & 0xFE; + } + else if (addr == 0x6A) + { + if (piix_type == 1) + return card_piix[addr] & 0x07; + else if (piix_type == 3) + return card_piix[addr] & 0xD1; + } + else if (addr == 0x6B) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 0x80; + } + else if (addr == 0x70) + { + if (piix_type == 1) + return card_piix[addr] & 0xCF; + else if (piix_type == 3) + return card_piix[addr] & 0xEF; + } + else if (addr == 0x71) + { + if (piix_type == 1) + return card_piix[addr] & 0xCF; + else if (piix_type == 3) + return 0; + } + else if (addr == 0x76) + { + if (piix_type == 1) + return card_piix[addr] & 0x8F; + else if (piix_type == 3) + return card_piix[addr] & 0x87; + } + else if (addr == 0x77) + { + if (piix_type == 1) + return card_piix[addr] & 0x8F; + else if (piix_type == 3) + return card_piix[addr] & 0x87; + } + else if (addr == 0x80) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 0x7F; + } + else if (addr == 0x82) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 0x0F; + } + else if (addr == 0xA0) + { + return card_piix[addr] & 0x1F; + } + else if (addr == 0xA3) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 1; + } + else if (addr == 0xA7) + { + if (piix_type == 1) + return card_piix[addr] & 0xEF; + else if (piix_type == 3) + return card_piix[addr]; + } + else if (addr == 0xAB) + { + if (piix_type == 1) + return card_piix[addr] & 0xFE; + else if (piix_type == 3) + return card_piix[addr]; + } + else + return card_piix[addr]; + } +} + +struct +{ + uint8_t command; + uint8_t status; + uint32_t ptr, ptr_cur; + int count; + uint32_t addr; + int eot; +} piix_busmaster[2]; + +static void piix_bus_master_next_addr(int channel) +{ + piix_busmaster[channel].addr = ((*(uint32_t *)(&ram[piix_busmaster[channel].ptr_cur])) & ~1) % (mem_size * 1024); + piix_busmaster[channel].count = (*(uint32_t *)(&ram[piix_busmaster[channel].ptr_cur + 4])) & 0xfffe; + piix_busmaster[channel].eot = (*(uint32_t *)(&ram[piix_busmaster[channel].ptr_cur + 4])) >> 31; + piix_busmaster[channel].ptr_cur += 8; +// pclog("New DMA settings on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); +} + +void piix_bus_master_write(uint16_t port, uint8_t val, void *priv) +{ + int channel = (port & 8) ? 1 : 0; +// pclog("PIIX Bus Master write %04X %02X %04x:%08x\n", port, val, CS, pc); + switch (port & 7) + { + case 0: + if ((val & 1) && !(piix_busmaster[channel].command & 1)) /*Start*/ + { + piix_busmaster[channel].ptr_cur = piix_busmaster[channel].ptr; + piix_bus_master_next_addr(channel); + piix_busmaster[channel].status |= 1; + } + if (!(val & 1) && (piix_busmaster[channel].command & 1)) /*Stop*/ + piix_busmaster[channel].status &= ~1; + + piix_busmaster[channel].command = val; + break; + case 2: + piix_busmaster[channel].status = (val & 0x60) | ((piix_busmaster[channel].status & ~val) & 6) | (piix_busmaster[channel].status & 1); + break; + case 4: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffffff00) | val; + piix_busmaster[channel].ptr %= (mem_size * 1024); + break; + case 5: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffff00ff) | (val << 8); + piix_busmaster[channel].ptr %= (mem_size * 1024); + break; + case 6: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xff00ffff) | (val << 16); + piix_busmaster[channel].ptr %= (mem_size * 1024); + break; + case 7: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0x00ffffff) | (val << 24); + piix_busmaster[channel].ptr %= (mem_size * 1024); + break; + + } +} + +uint8_t piix_bus_master_read(uint16_t port, void *priv) +{ + int channel = (port & 8) ? 1 : 0; +// pclog("PIIX Bus Master read %04X %04x:%08x\n", port, CS, pc); + switch (port & 7) + { + case 0: + return piix_busmaster[channel].command; + case 2: + return piix_busmaster[channel].status; + case 4: + return piix_busmaster[channel].ptr; + case 5: + return piix_busmaster[channel].ptr >> 8; + case 6: + return piix_busmaster[channel].ptr >> 16; + case 7: + return piix_busmaster[channel].ptr >> 24; + } + return 0xff; +} + +int piix_bus_master_sector_read(int channel, uint8_t *data) +{ + int transferred = 0; + + if (!(piix_busmaster[channel].status & 1)) + return 1; /*DMA disabled*/ + + while (transferred < 512) + { + if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) + fatal("DMA on channel %i - Read count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + mem_invalidate_range(piix_busmaster[channel].addr, piix_busmaster[channel].addr+511); + + if (piix_busmaster[channel].count < (512 - transferred)) + { +// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); + memcpy(&ram[piix_busmaster[channel].addr], data + transferred, piix_busmaster[channel].count); + transferred += piix_busmaster[channel].count; + piix_busmaster[channel].addr += piix_busmaster[channel].count; + piix_busmaster[channel].addr %= (mem_size * 1024); + piix_busmaster[channel].count = 0; + } + else + { +// pclog("Transferring larger - %i bytes\n", 512 - transferred); + memcpy(&ram[piix_busmaster[channel].addr], data + transferred, 512 - transferred); + piix_busmaster[channel].addr += (512 - transferred); + piix_busmaster[channel].count -= (512 - transferred); + transferred += (512 - transferred); + } + +// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (!piix_busmaster[channel].count) + { +// pclog("DMA on channel %i - block over\n", channel); + if (piix_busmaster[channel].eot) /*End of transfer?*/ + { +// pclog("DMA on channel %i - transfer over\n", channel); + piix_busmaster[channel].status &= ~1; + } + else + piix_bus_master_next_addr(channel); + } + } + return 0; +} +int piix_bus_master_sector_write(int channel, uint8_t *data) +{ + int transferred = 0; + + if (!(piix_busmaster[channel].status & 1)) + return 1; /*DMA disabled*/ + + while (transferred < 512) + { + if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) + fatal("DMA on channel %i - Write count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (piix_busmaster[channel].count < (512 - transferred)) + { +// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); + memcpy(data + transferred, &ram[piix_busmaster[channel].addr], piix_busmaster[channel].count); + transferred += piix_busmaster[channel].count; + piix_busmaster[channel].addr += piix_busmaster[channel].count; + piix_busmaster[channel].addr %= (mem_size * 1024); + piix_busmaster[channel].count = 0; + } + else + { +// pclog("Transferring larger - %i bytes\n", 512 - transferred); + memcpy(data + transferred, &ram[piix_busmaster[channel].addr], 512 - transferred); + piix_busmaster[channel].addr += (512 - transferred); + piix_busmaster[channel].count -= (512 - transferred); + transferred += (512 - transferred); + } + +// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (!piix_busmaster[channel].count) + { +// pclog("DMA on channel %i - block over\n", channel); + if (piix_busmaster[channel].eot) /*End of transfer?*/ + { +// pclog("DMA on channel %i - transfer over\n", channel); + piix_busmaster[channel].status &= ~1; + } + else + piix_bus_master_next_addr(channel); + } + } + return 0; +} + +void piix_bus_master_set_irq(int channel) +{ + piix_busmaster[channel].status |= 4; +} + +void piix_init(int card) +{ + pci_add_specific(card, piix_read, piix_write, NULL); + + memset(card_piix, 0, 256); + card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/ + card_piix[0x02] = 0x2e; card_piix[0x03] = 0x12; /*82371FB (PIIX)*/ + card_piix[0x04] = 0x07; card_piix[0x05] = 0x00; + card_piix[0x06] = 0x00; card_piix[0x07] = 0x02; + card_piix[0x08] = 0x00; /*A0 stepping*/ + card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06; + card_piix[0x0e] = 0x80; /*Multi-function device*/ + card_piix[0x4c] = 0x4d; + card_piix[0x4e] = 0x03; + card_piix[0x60] = card_piix[0x61] = card_piix[0x62] = card_piix[0x63] = 0x80; + card_piix[0x69] = 0x02; + card_piix[0x70] = card_piix[0x71] = 0x80; + card_piix[0x76] = card_piix[0x77] = 0x0c; + card_piix[0x78] = 0x02; card_piix[0x79] = 0x00; + card_piix[0xa0] = 0x08; + card_piix[0xa2] = card_piix[0xa3] = 0x00; + card_piix[0xa4] = card_piix[0xa5] = card_piix[0xa6] = card_piix[0xa7] = 0x00; + card_piix[0xa8] = 0x0f; + card_piix[0xaa] = card_piix[0xab] = 0x00; + card_piix[0xac] = 0x00; + card_piix[0xae] = 0x00; + + card_piix_ide[0x00] = 0x86; card_piix_ide[0x01] = 0x80; /*Intel*/ + card_piix_ide[0x02] = 0x30; card_piix_ide[0x03] = 0x12; /*82371FB (PIIX)*/ + card_piix_ide[0x04] = 0x00; card_piix_ide[0x05] = 0x00; + card_piix_ide[0x06] = 0x80; card_piix_ide[0x07] = 0x02; + card_piix_ide[0x08] = 0x00; + card_piix_ide[0x09] = 0x80; card_piix_ide[0x0a] = 0x01; card_piix_ide[0x0b] = 0x01; + card_piix_ide[0x0d] = 0x00; + card_piix_ide[0x0e] = 0x00; + card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ + card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00; + card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00; + + piix_type = 1; + + ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq); +} + +void piix3_init(int card) +{ + pci_add_specific(card, piix_read, piix_write, NULL); + + memset(card_piix, 0, 256); + card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/ + card_piix[0x02] = 0x00; card_piix[0x03] = 0x70; /*82371SB (PIIX3)*/ + card_piix[0x04] = 0x07; card_piix[0x05] = 0x00; + card_piix[0x06] = 0x00; card_piix[0x07] = 0x02; + card_piix[0x08] = 0x00; /*A0 stepping*/ + card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06; + card_piix[0x0e] = 0x80; /*Multi-function device*/ + card_piix[0x4c] = 0x4d; + card_piix[0x4e] = card_piix[0x4f] = 0x03; + card_piix[0x60] = card_piix[0x61] = card_piix[0x62] = card_piix[0x63] = 0x80; + card_piix[0x69] = 0x02; + card_piix[0x70] = 0x80; + card_piix[0x76] = card_piix[0x77] = 0x0c; + card_piix[0x78] = 0x02; card_piix[0x79] = 0x00; + card_piix[0xa0] = 0x08; + card_piix[0xa2] = card_piix[0xa3] = 0x00; + card_piix[0xa4] = card_piix[0xa5] = card_piix[0xa6] = card_piix[0xa7] = 0x00; + card_piix[0xa8] = 0x0f; + card_piix[0xaa] = card_piix[0xab] = 0x00; + card_piix[0xac] = 0x00; + card_piix[0xae] = 0x00; + + card_piix_ide[0x00] = 0x86; card_piix_ide[0x01] = 0x80; /*Intel*/ + card_piix_ide[0x02] = 0x10; card_piix_ide[0x03] = 0x70; /*82371SB (PIIX3)*/ + card_piix_ide[0x04] = 0x00; card_piix_ide[0x05] = 0x00; + card_piix_ide[0x06] = 0x80; card_piix_ide[0x07] = 0x02; + card_piix_ide[0x08] = 0x00; + card_piix_ide[0x09] = 0x80; card_piix_ide[0x0a] = 0x01; card_piix_ide[0x0b] = 0x01; + card_piix_ide[0x0d] = 0x00; + card_piix_ide[0x0e] = 0x00; + card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ + card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00; + card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00; + card_piix_ide[0x44] = 0x00; + + piix_type = 3; + + ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq); +} diff --git a/src/piix.h b/src/piix.h new file mode 100644 index 000000000..9bac729e6 --- /dev/null +++ b/src/piix.h @@ -0,0 +1,2 @@ +void piix_init(int card); +void piix3_init(int card); diff --git a/src/pit.c b/src/pit.c new file mode 100644 index 000000000..20baa7ee2 --- /dev/null +++ b/src/pit.c @@ -0,0 +1,627 @@ +/*IBM AT - + Write B0 + Write aa55 + Expects aa55 back*/ + +#include +#include "ibm.h" + +#include "cpu.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "timer.h" +#include "video.h" +#include "model.h" +/*B0 to 40, two writes to 43, then two reads - value does not change!*/ +/*B4 to 40, two writes to 43, then two reads - value _does_ change!*/ +//Tyrian writes 4300 or 17512 +int displine; + +double PITCONST; +float cpuclock; +float isa_timing, bus_timing; + +int firsttime=1; +void setpitclock(float clock) +{ +// printf("PIT clock %f\n",clock); + cpuclock=clock; + PITCONST=clock/1193182.0; + CGACONST=(clock/(19687503.0/11.0)); + MDACONST=(clock/2032125.0); + VGACONST1=(clock/25175000.0); + VGACONST2=(clock/28322000.0); + isa_timing = clock/8000000.0; + bus_timing = clock/(double)cpu_busspeed; + video_updatetiming(); +// pclog("PITCONST=%f CGACONST=%f\n", PITCONST, CGACONST); +// pclog("CPUMULTI=%g\n", ((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed)); + + xt_cpu_multi = (int)((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); +// pclog("egacycles %i egacycles2 %i temp %f clock %f\n",egacycles,egacycles2,temp,clock); +/* if (video_recalctimings) + video_recalctimings();*/ + RTCCONST=clock/32768.0; + TIMER_USEC = (int)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); + device_speed_changed(); +} + +//#define PITCONST (8000000.0/1193000.0) +//#define PITCONST (cpuclock/1193000.0) +void pit_reset() +{ + memset(&pit,0,sizeof(PIT)); + pit.l[0]=0xFFFF; pit.c[0]=0xFFFF*PITCONST; + pit.l[1]=0xFFFF; pit.c[1]=0xFFFF*PITCONST; + pit.l[2]=0xFFFF; pit.c[2]=0xFFFF*PITCONST; + pit.m[0]=pit.m[1]=pit.m[2]=0; + pit.ctrls[0]=pit.ctrls[1]=pit.ctrls[2]=0; + pit.thit[0]=1; + spkstat=0; + pit.gate[0] = pit.gate[1] = 1; + pit.gate[2] = 0; + pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; +} + +void clearpit() +{ + pit.c[0]=(pit.l[0]<<2); +} + +float pit_timer0_freq() +{ + if (pit.l[0]) + return 1193182.0f/(float)pit.l[0]; + else + return 1193182.0f/(float)0x10000; +} + +static void (*pit_set_out_funcs[3])(int new_out, int old_out); + +static void pit_set_out(int t, int out) +{ + pit_set_out_funcs[t](out, pit.out[t]); + pit.out[t] = out; +} + +static void pit_load(int t) +{ + int l = pit.l[t] ? pit.l[t] : 0x10000; + timer_process(); + pit.newcount[t] = 0; + pit.disabled[t] = 0; +// pclog("pit_load: t=%i l=%x\n", t, l); + switch (pit.m[t]) + { + case 0: /*Interrupt on terminal count*/ + pit.count[t] = l; + pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 0); + pit.thit[t] = 0; + pit.enabled[t] = pit.gate[t]; + break; + case 1: /*Hardware retriggerable one-shot*/ + pit.enabled[t] = 1; + break; + case 2: /*Rate generator*/ + if (pit.initial[t]) + { + pit.count[t] = l - 1; + pit.c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = pit.gate[t]; + break; + case 3: /*Square wave mode*/ + if (pit.initial[t]) + { + pit.count[t] = l; + pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = pit.gate[t]; +// pclog("pit_load: square wave mode c=%x\n", pit.c[t]); + break; + case 4: /*Software triggered stobe*/ + if (!pit.thit[t] && !pit.initial[t]) + pit.newcount[t] = 1; + else + { + pit.count[t] = l; + pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 0); + pit.thit[t] = 0; + } + pit.enabled[t] = pit.gate[t]; + break; + case 5: /*Hardware triggered stobe*/ + pit.enabled[t] = 1; + break; + } + pit.initial[t] = 0; + pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; + timer_update_outstanding(); +// pclog("pit_load: t=%i running=%i thit=%i enabled=%i m=%i l=%x c=%g gate=%i\n", t, pit.running[t], pit.thit[t], pit.enabled[t], pit.m[t], pit.l[t], pit.c[t], pit.gate[t]); +} + +void pit_set_gate(int t, int gate) +{ + int l = pit.l[t] ? pit.l[t] : 0x10000; + + if (pit.disabled[t]) + { + pit.gate[t] = gate; + return; + } + + timer_process(); + switch (pit.m[t]) + { + case 0: /*Interrupt on terminal count*/ + case 4: /*Software triggered stobe*/ + pit.enabled[t] = gate; + break; + case 1: /*Hardware retriggerable one-shot*/ + case 5: /*Hardware triggered stobe*/ + if (gate && !pit.gate[t]) + { + pit.count[t] = l; + pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 0); + pit.thit[t] = 0; + pit.enabled[t] = 1; + } + break; + case 2: /*Rate generator*/ + if (gate && !pit.gate[t]) + { + pit.count[t] = l - 1; + pit.c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = gate; + break; + case 3: /*Square wave mode*/ + if (gate && !pit.gate[t]) + { + pit.count[t] = l; + pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = gate; + break; + } + pit.gate[t] = gate; + pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; + timer_update_outstanding(); +// pclog("pit_set_gate: t=%i gate=%i\n", t, gate); +} + +static void pit_over(int t) +{ + int l = pit.l[t] ? pit.l[t] : 0x10000; + if (pit.disabled[t]) + { + pit.count[t] += 0xffff; + pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + return; + } + +// if (!t) pclog("pit_over: t=%i l=%x c=%x %i hit=%i\n", t, pit.l[t], pit.c[t], pit.c[t] >> TIMER_SHIFT, pit.thit[t]); + switch (pit.m[t]) + { + case 0: /*Interrupt on terminal count*/ + case 1: /*Hardware retriggerable one-shot*/ + if (!pit.thit[t]) + pit_set_out(t, 1); + pit.thit[t] = 1; + pit.count[t] += 0xffff; + pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + break; + case 2: /*Rate generator*/ + pit.count[t] += l; + pit.c[t] += (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 0); + pit_set_out(t, 1); + break; + case 3: /*Square wave mode*/ + if (pit.out[t]) + { + pit_set_out(t, 0); + pit.count[t] += (l >> 1); + pit.c[t] += (int)(((l >> 1) << TIMER_SHIFT) * PITCONST); + } + else + { + pit_set_out(t, 1); + pit.count[t] += ((l + 1) >> 1); + pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + } +// if (!t) pclog("pit_over: square wave mode c=%x %lli %f\n", pit.c[t], tsc, PITCONST); + break; + case 4: /*Software triggered strove*/ + if (!pit.thit[t]) + { + pit_set_out(t, 0); + pit_set_out(t, 1); + } + if (pit.newcount[t]) + { + pit.newcount[t] = 0; + pit.count[t] += l; + pit.c[t] += (int)((l << TIMER_SHIFT) * PITCONST); + } + else + { + pit.thit[t] = 1; + pit.count[t] += 0xffff; + pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + } + break; + case 5: /*Hardware triggered strove*/ + if (!pit.thit[t]) + { + pit_set_out(t, 0); + pit_set_out(t, 1); + } + pit.thit[t] = 1; + pit.count[t] += 0xffff; + pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + break; + } + pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; +} + +int pit_get_timer_0() +{ + int read = (int)((pit.c[0] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; +//pclog("pit_get_timer_0: t=%i using_timer=%i m=%i\n", 0, pit.using_timer[0], pit.m[0]); + if (pit.m[0] == 2) + read++; + if (read < 0) + read = 0; + if (read > 0x10000) + read = 0x10000; + if (pit.m[0] == 3) + read <<= 1; + return read; +} + +static int pit_read_timer(int t) +{ + timer_clock(); +// pclog("pit_read_timer: t=%i using_timer=%i m=%i\n", t, pit.using_timer[t], pit.m[t]); + if (pit.using_timer[t]) + { + int read = (int)((pit.c[t] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; + if (pit.m[t] == 2) + read++; + if (read < 0) + read = 0; + if (read > 0x10000) + read = 0x10000; + if (pit.m[t] == 3) + read <<= 1; + return read; + } + if (pit.m[t] == 2) + return pit.count[t] + 1; + return pit.count[t]; +} + +extern int ins; +void pit_write(uint16_t addr, uint8_t val, void *priv) +{ + int t; + cycles -= (int)PITCONST; +// /*if (val != 0x40) */pclog("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,pc,ins, pit.gate[0]); + + switch (addr&3) + { + case 3: /*CTRL*/ + if ((val&0xC0)==0xC0) + { + if (!(val&0x20)) + { + if (val & 2) + pit.rl[0] = pit.using_timer[0] ? ((int)(pit.c[0] / PITCONST) >> TIMER_SHIFT) : pit.count[0]; + if (val & 4) + pit.rl[1] = pit.using_timer[1] ? ((int)(pit.c[1] / PITCONST) >> TIMER_SHIFT) : pit.count[1]; + if (val & 8) + pit.rl[2] = pit.using_timer[2] ? ((int)(pit.c[2] / PITCONST) >> TIMER_SHIFT) : pit.count[2]; + } + if (!(val & 0x10)) + { + if (val & 2) + { + pit.read_status[0] = (pit.ctrls[0] & 0x3f) | 0x40 | (pit.out[0] ? 0x80 : 0); + pit.do_read_status[0] = 1; + } + if (val & 4) + { + pit.read_status[1] = (pit.ctrls[1] & 0x3f) | 0x40 | (pit.out[1] ? 0x80 : 0); + pit.do_read_status[1] = 1; + } + if (val & 8) + { + pit.read_status[2] = (pit.ctrls[2] & 0x3f) | 0x40 | (pit.out[2] ? 0x80 : 0); + pit.do_read_status[2] = 1; + } + } + return; + } + t = val >> 6; + pit.ctrl=val; + if ((val>>7)==3) + { + printf("Bad PIT reg select\n"); + return; +// dumpregs(); +// exit(-1); + } +// printf("CTRL write %02X\n",val); + if (!(pit.ctrl&0x30)) + { + pit.rl[t] = pit_read_timer(t); +// pclog("Timer latch %f %04X %04X\n",pit.c[0],pit.rl[0],pit.l[0]); + pit.ctrl |= 0x30; + pit.rereadlatch[t] = 0; + pit.rm[t] = 3; + pit.latched[t] = 1; + } + else + { + pit.ctrls[val>>6] = val; + pit.rm[val>>6]=pit.wm[val>>6]=(pit.ctrl>>4)&3; + pit.m[val>>6]=(val>>1)&7; + if (pit.m[val>>6]>5) + pit.m[val>>6]&=3; + if (!(pit.rm[val>>6])) + { + pit.rm[val>>6]=3; + pit.rl[t] = pit_read_timer(t); + } + pit.rereadlatch[val>>6]=1; + if ((val>>6)==2) ppispeakon=speakon=(pit.m[2]==0)?0:1; + pit.initial[t] = 1; + if (!pit.m[val >> 6]) + pit_set_out(val >> 6, 0); + else + pit_set_out(val >> 6, 1); + pit.disabled[val >> 6] = 1; +// pclog("ppispeakon %i\n",ppispeakon); + } + pit.wp=0; + pit.thit[pit.ctrl>>6]=0; + break; + case 0: case 1: case 2: /*Timers*/ + t=addr&3; +// if (t==2) ppispeakon=speakon=0; +// pclog("Write timer %02X %i\n",pit.ctrls[t],pit.wm[t]); + switch (pit.wm[t]) + { + case 1: + pit.l[t]=val; +// pit.thit[t]=0; + pit_load(t); +// pit.c[t]=pit.l[t]*PITCONST; +// if (!t) +// picintc(1); + break; + case 2: + pit.l[t]=(val<<8); +// pit.thit[t]=0; + pit_load(t); +// pit.c[t]=pit.l[t]*PITCONST; +// if (!t) +// picintc(1); + break; + case 0: + pit.l[t]&=0xFF; + pit.l[t]|=(val<<8); + pit_load(t); +// pit.c[t]=pit.l[t]*PITCONST; +// pclog("%04X %f\n",pit.l[t],pit.c[t]); +// pit.thit[t]=0; + pit.wm[t]=3; +// if (!t) +// picintc(1); + break; + case 3: + pit.l[t]&=0xFF00; + pit.l[t]|=val; + pit.wm[t]=0; + break; + } + speakval=(((float)pit.l[2]/(float)pit.l[0])*0x4000)-0x2000; +// printf("Speakval now %i\n",speakval); +// if (speakval>0x2000) +// printf("Speaker overflow - %i %i %04X %04X\n",pit.l[0],pit.l[2],pit.l[0],pit.l[2]); + if (speakval>0x2000) speakval=0x2000; +/* if (!pit.l[t]) + { + pit.l[t]|=0x10000; + pit.c[t]=pit.l[t]*PITCONST; + }*/ + break; + } +} + +uint8_t pit_read(uint16_t addr, void *priv) +{ + int t; + uint8_t temp; + cycles -= (int)PITCONST; +// printf("Read PIT %04X ",addr); + switch (addr&3) + { + case 0: case 1: case 2: /*Timers*/ + t = addr & 3; + if (pit.do_read_status[t]) + { + pit.do_read_status[t] = 0; + temp = pit.read_status[t]; + break; + } + if (pit.rereadlatch[addr & 3] && !pit.latched[addr & 3]) + { + pit.rereadlatch[addr & 3] = 0; + pit.rl[t] = pit_read_timer(t); + } + switch (pit.rm[addr & 3]) + { + case 0: + temp = pit.rl[addr & 3] >> 8; + pit.rm[addr & 3] = 3; + pit.latched[addr & 3] = 0; + pit.rereadlatch[addr & 3] = 1; + break; + case 1: + temp = (pit.rl[addr & 3]) & 0xFF; + pit.latched[addr & 3] = 0; + pit.rereadlatch[addr & 3] = 1; + break; + case 2: + temp = (pit.rl[addr & 3]) >> 8; + pit.latched[addr & 3] = 0; + pit.rereadlatch[addr & 3] = 1; + break; + case 3: + temp = (pit.rl[addr & 3]) & 0xFF; + if (pit.m[addr & 3] & 0x80) + pit.m[addr & 3] &= 7; + else + pit.rm[addr & 3] = 0; + break; + } + break; + case 3: /*Control*/ + temp = pit.ctrl; + break; + } +// pclog("%02X\n", temp); +// printf("%02X %i %i %04X:%04X %i\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc, ins); + return temp; +} + +void pit_poll() +{ +// printf("Poll pit %f %f %f\n",pit.c[0],pit.c[1],pit.c[2]); + if (pit.c[0] < 1 && pit.running[0]) + pit_over(0); + if (pit.c[1] < 1 && pit.running[1]) + pit_over(1); + if (pit.c[2] < 1 && pit.running[2]) + pit_over(2); +} + +void pit_timer_over(void *p) +{ + int timer = (int) p; +// pclog("pit_timer_over %i\n", timer); + + pit_over(timer); +} + +void pit_clock(int t) +{ + if (pit.thit[t] || !pit.enabled[t]) + return; + + if (pit.using_timer[t]) + return; + + pit.count[t] -= (pit.m[t] == 3) ? 2 : 1; + if (!pit.count[t]) + pit_over(t); +} + +void pit_set_using_timer(int t, int using_timer) +{ +// pclog("pit_set_using_timer: t=%i using_timer=%i\n", t, using_timer); + timer_process(); + if (pit.using_timer[t] && !using_timer) + pit.count[t] = pit_read_timer(t); + if (!pit.using_timer[t] && using_timer) + pit.c[t] = (int)((pit.count[t] << TIMER_SHIFT) * PITCONST); + pit.using_timer[t] = using_timer; + pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; + timer_update_outstanding(); +} + +void pit_set_out_func(int t, void (*func)(int new_out, int old_out)) +{ + pit_set_out_funcs[t] = func; +} + +void pit_null_timer(int new_out, int old_out) +{ +} + +void pit_irq0_timer(int new_out, int old_out) +{ + if (new_out && !old_out) + picint(1); + if (!new_out) + picintc(1); +} + +void pit_irq0_timer_pcjr(int new_out, int old_out) +{ + if (new_out && !old_out) + { + picint(1); + pit_clock(1); + } + if (!new_out) + picintc(1); +} + +void pit_refresh_timer_xt(int new_out, int old_out) +{ + if (new_out && !old_out) + dma_channel_read(0); +} + +void pit_refresh_timer_at(int new_out, int old_out) +{ + if (new_out && !old_out) + ppi.pb ^= 0x10; +} + +void pit_speaker_timer(int new_out, int old_out) +{ + int l; + + speaker_update(); + + l = pit.l[2] ? pit.l[2] : 0x10000; + if (l < 25) + speakon = 0; + else + speakon = new_out; + ppispeakon = new_out; +} + + +void pit_init() +{ + io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, NULL); + pit.gate[0] = pit.gate[1] = 1; + pit.gate[2] = 0; + pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; + + timer_add(pit_timer_over, &pit.c[0], &pit.running[0], (void *)0); + timer_add(pit_timer_over, &pit.c[1], &pit.running[1], (void *)1); + timer_add(pit_timer_over, &pit.c[2], &pit.running[2], (void *)2); + + pit_set_out_func(0, pit_irq0_timer); + pit_set_out_func(1, pit_null_timer); + pit_set_out_func(2, pit_speaker_timer); +} diff --git a/src/pit.h b/src/pit.h new file mode 100644 index 000000000..a9d5cbc66 --- /dev/null +++ b/src/pit.h @@ -0,0 +1,16 @@ +extern double PITCONST; +extern float cpuclock; +void pit_init(); +void pit_reset(); +void pit_set_gate(int channel, int gate); +void pit_set_using_timer(int t, int using_timer); +void pit_set_out_func(int t, void (*func)(int new_out, int old_out)); +void pit_clock(int t); + + +void pit_null_timer(int new_out, int old_out); +void pit_irq0_timer(int new_out, int old_out); +void pit_irq0_timer_pcjr(int new_out, int old_out); +void pit_refresh_timer_xt(int new_out, int old_out); +void pit_refresh_timer_at(int new_out, int old_out); +void pit_speaker_timer(int new_out, int old_out); diff --git a/src/plat-dinput.h b/src/plat-dinput.h new file mode 100644 index 000000000..442729dab --- /dev/null +++ b/src/plat-dinput.h @@ -0,0 +1 @@ +extern LPDIRECTINPUT lpdi; diff --git a/src/plat-joystick.h b/src/plat-joystick.h new file mode 100644 index 000000000..2b789f5f8 --- /dev/null +++ b/src/plat-joystick.h @@ -0,0 +1,65 @@ +#ifdef __cplusplus +extern "C" { +#endif + void joystick_init(); + void joystick_close(); + void joystick_poll(); + + typedef struct plat_joystick_t + { + char name[64]; + + int a[8]; + int b[32]; + int p[4]; + + struct + { + char name[32]; + int id; + } axis[8]; + + struct + { + char name[32]; + int id; + } button[32]; + + struct + { + char name[32]; + int id; + } pov[4]; + + int nr_axes; + int nr_buttons; + int nr_povs; + } plat_joystick_t; + + #define MAX_PLAT_JOYSTICKS 8 + + extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; + extern int joysticks_present; + + #define POV_X 0x80000000 + #define POV_Y 0x40000000 + + typedef struct joystick_t + { + int axis[8]; + int button[32]; + int pov[4]; + + int plat_joystick_nr; + int axis_mapping[8]; + int button_mapping[32]; + } joystick_t; + + #define MAX_JOYSTICKS 4 + extern joystick_t joystick_state[MAX_JOYSTICKS]; + + #define JOYSTICK_PRESENT(n) (joystick_state[n].plat_joystick_nr != 0) + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/plat-keyboard.h b/src/plat-keyboard.h new file mode 100644 index 000000000..6dad21d6e --- /dev/null +++ b/src/plat-keyboard.h @@ -0,0 +1,19 @@ +#ifdef __cplusplus +extern "C" { +#endif + void keyboard_init(); + void keyboard_close(); + void keyboard_poll_host(); + extern int pcem_key[272]; + extern int rawinputkey[272]; + +#ifndef __unix + #define KEY_LCONTROL 0x1d + #define KEY_RCONTROL (0x1d | 0x80) + #define KEY_END (0x4f | 0x80) +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/src/plat-midi.h b/src/plat-midi.h new file mode 100644 index 000000000..ec0a469da --- /dev/null +++ b/src/plat-midi.h @@ -0,0 +1,3 @@ +void midi_init(); +void midi_close(); +void midi_write(uint8_t val); diff --git a/src/plat-mouse.h b/src/plat-mouse.h new file mode 100644 index 000000000..749f27bda --- /dev/null +++ b/src/plat-mouse.h @@ -0,0 +1,13 @@ +#ifdef __cplusplus +extern "C" { +#endif + + void mouse_init(); + void mouse_close(); + extern int mouse_buttons; + void mouse_poll_host(); + void mouse_get_mickeys(int *x, int *y); + extern int mousecapture; +#ifdef __cplusplus +} +#endif diff --git a/src/ppi.c b/src/ppi.c new file mode 100644 index 000000000..246116414 --- /dev/null +++ b/src/ppi.c @@ -0,0 +1,19 @@ +/*IBM 5150 cassette nonsense + Calls F979 twice + Expects CX to be nonzero, BX >$410 and <$540 + CX is loops between bit 4 of $62 changing + BX is timer difference between calls + */ + +#include "ibm.h" +#include "pit.h" + +#include "plat-keyboard.h" +#include "plat-mouse.h" + +void ppi_reset() +{ + ppi.pa=0x0;//0x1D; + ppi.pb=0x40; +} + diff --git a/src/ps1.c b/src/ps1.c new file mode 100644 index 000000000..988bde71a --- /dev/null +++ b/src/ps1.c @@ -0,0 +1,295 @@ +#include "ibm.h" +#include "mem.h" +#include "ps1.h" +#include "rom.h" +#include "lpt.h" + +static rom_t ps1_high_rom; +static uint8_t ps1_92, ps1_94, ps1_102, ps1_103, ps1_104, ps1_105, ps1_190; +static int ps1_e0_addr; +static uint8_t ps1_e0_regs[256]; + +static struct +{ + uint8_t status, int_status; + uint8_t attention, ctrl; +} ps1_hd; + +uint8_t ps1_read(uint16_t port, void *p) +{ + uint8_t temp; + + switch (port) + { + case 0x91: + return 0; + case 0x92: + return ps1_92; + case 0x94: + return ps1_94; + case 0x102: + return ps1_102 | 8; + case 0x103: + return ps1_103; + case 0x104: + return ps1_104; + case 0x105: + return ps1_105; + case 0x190: + return ps1_190; + + case 0x322: + temp = ps1_hd.status; + break; + case 0x324: + temp = ps1_hd.int_status; + ps1_hd.int_status &= ~0x02; + break; + + default: + temp = 0xff; + break; + } + + return temp; +} + +void ps1_write(uint16_t port, uint8_t val, void *p) +{ + switch (port) + { + case 0x0092: + ps1_92 = val; + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + case 0x94: + ps1_94 = val; + break; + case 0x102: + lpt1_remove(); + if (val & 0x04) + serial1_init(0x3f8, 4); + else + serial1_remove(); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps1_102 = val; + break; + case 0x103: + ps1_103 = val; + break; + case 0x104: + ps1_104 = val; + break; + case 0x105: + ps1_105 = val; + break; + case 0x190: + ps1_190 = val; + break; + + case 0x322: + ps1_hd.ctrl = val; + if (val & 0x80) + ps1_hd.status |= 0x02; + break; + case 0x324: + ps1_hd.attention = val & 0xf0; + if (ps1_hd.attention) + ps1_hd.status = 0x14; + break; + } +} + +void ps1mb_init() +{ + io_sethandler(0x0091, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0102, 0x0004, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0190, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0320, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0322, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0324, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + + rom_init(&ps1_high_rom, + "roms/ibmps1es/f80000.bin", + 0xf80000, + 0x80000, + 0x7ffff, + 0, + MEM_MAPPING_EXTERNAL); +/* rom_init_interleaved(&ps1_high_rom, + "roms/ibmps1es/ibm_1057757_24-05-90.bin", + "roms/ibmps1es/ibm_1057757_29-15-90.bin", + 0xfc0000, + 0x40000, + 0x3ffff, + 0, + MEM_MAPPING_EXTERNAL);*/ + ps1_190 = 0; + + lpt1_remove(); + lpt2_remove(); + lpt1_init(0x3bc); + + serial1_remove(); + serial2_remove(); + + memset(&ps1_hd, 0, sizeof(ps1_hd)); +} + +/*PS/1 Model 2121. + + This is similar to the model 2011 but some of the functionality has moved to a + chip at ports 0xe0 (index)/0xe1 (data). The only functions I have identified + are enables for the first 512kb and next 128kb of RAM, in bits 0 of registers + 0 and 1 respectively. + + Port 0x105 has bit 7 forced high. Without this 128kb of memory will be missed + by the BIOS on cold boots. + + The reserved 384kb is remapped to the top of extended memory. If this is not + done then you get an error on startup. +*/ +static uint8_t ps1_m2121_read(uint16_t port, void *p) +{ + uint8_t temp; + + switch (port) + { + case 0x91: + return 0; + case 0x92: + return ps1_92; + case 0x94: + return ps1_94; + case 0xe1: + return ps1_e0_regs[ps1_e0_addr]; + case 0x102: + return ps1_102; + case 0x103: + return ps1_103; + case 0x104: + return ps1_104; + case 0x105: + return ps1_105 | 0x80; + case 0x190: + return ps1_190; + + default: + temp = 0xff; + break; + } + + return temp; +} + +static void ps1_m2121_recalc_memory() +{ + /*Enable first 512kb*/ + mem_set_mem_state(0x00000, 0x80000, (ps1_e0_regs[0] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + /*Enable 512-640kb*/ + mem_set_mem_state(0x80000, 0x20000, (ps1_e0_regs[1] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); +} + +void ps1_m2121_write(uint16_t port, uint8_t val, void *p) +{ + switch (port) + { + case 0x0092: + if (val & 1) + softresetx86(); + ps1_92 = val & ~1; + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + case 0x94: + ps1_94 = val; + break; + case 0xe0: + ps1_e0_addr = val; + break; + case 0xe1: + ps1_e0_regs[ps1_e0_addr] = val; + ps1_m2121_recalc_memory(); + break; + case 0x102: + lpt1_remove(); + if (val & 0x04) + serial1_init(0x3f8, 4); + else + serial1_remove(); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps1_102 = val; + break; + case 0x103: + ps1_103 = val; + break; + case 0x104: + ps1_104 = val; + break; + case 0x105: + ps1_105 = val; + break; + case 0x190: + ps1_190 = val; + break; + } +} + +void ps1mb_m2121_init() +{ + io_sethandler(0x0091, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x00e0, 0x0002, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0102, 0x0004, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0190, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + + rom_init(&ps1_high_rom, + "roms/ibmps1_2121/fc0000.bin", + 0xfc0000, + 0x40000, + 0x3ffff, + 0, + MEM_MAPPING_EXTERNAL); + ps1_190 = 0; + + lpt1_remove(); + lpt2_remove(); + lpt1_init(0x3bc); + + serial1_remove(); + serial2_remove(); + + mem_remap_top_384k(); +} diff --git a/src/ps1.h b/src/ps1.h new file mode 100644 index 000000000..4216fbc00 --- /dev/null +++ b/src/ps1.h @@ -0,0 +1,2 @@ +void ps1mb_init(); +void ps1mb_m2121_init(); diff --git a/src/resid-fp/AUTHORS b/src/resid-fp/AUTHORS new file mode 100644 index 000000000..cd2ca3fcc --- /dev/null +++ b/src/resid-fp/AUTHORS @@ -0,0 +1,4 @@ +Authors of reSID. + +Dag Lem: Designed and programmed complete emulation engine. +Antti S. Lankila: Support 6581 filter distortion, envelope & voice nonlinearities, output amp clipping effects. diff --git a/src/resid-fp/COPYING b/src/resid-fp/COPYING new file mode 100644 index 000000000..d60c31a97 --- /dev/null +++ b/src/resid-fp/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + + Copyright (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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) year 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. + + , 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/src/resid-fp/ChangeLog b/src/resid-fp/ChangeLog new file mode 100644 index 000000000..c12e828b9 --- /dev/null +++ b/src/resid-fp/ChangeLog @@ -0,0 +1,136 @@ +2008-12-05 Antti S. Lankila + + * Sync against V27 patch version. Filter updates described below. + + * Reduce Q maximum to 2.2 or so. This may still be slightly too much, + but it's hard to say exactly... + + * Arrange for about 3 dB boost of lowpass output that is independent + of state variable mixing or other feedback. This seems to produce + the right kind of sounds for songs like AMJ's Blasphemy. + + * Assume that bp is slightly louder than bp (= more distorted). + This seems to help against very large number of songs which sport + lead sounds and effects distorted in a smooth, bassy way. + + * Parameter tuneup. + +2008-10-31 Antti S. Lankila + + * Sync against V25 patch version. Filter updates described below. + + * Tweak filter algorithm to do some state variable mixing in the + 6581 code path. This corresponds with assumed output impedance of + the SID "amplifiers", and is separate effect to the output strip + backmixing. + + * Retire the V24 attempt of dynamically adjusting BP distortion + threshold. It doesn't really seem to work. + + * Increase Q value maximum to 2.5. This may be too much, but it sounds + fine to me. + + * JT's Star Ball was very distorted when played by V24. This related + to the hardclipping I had assumed to occur in the filter output amp, + but maybe that theory is incorrect. I now only add distortion to the + unfiltered voice path, but I'm not happy about it. + +2008-08-29 Antti S. Lankila + + * Optimized resampling to be about 2x faster through using aliasing + to increase passband width and hence reduce FIR length. + + * Fixed some valgrind warnings. + + * Added nuke_denormals() method to periodically flush these to zero, as + this can only be done for SSE registers by the FPU and we can't use + any in order to support CPUs older than P3. + + * Marco, Hannu and me developed a runtime switching system + that detects SSE from cpuinfo and calls some SSE routines when they + are compiled in and the CPU can support them. We lost only very + little performance, but gained compatibility to very, very old + hardware. + + * The old code for ST_lockup proved unnecessary, so it is now removed. + +2008-08-21 Antti S. Lankila + + * Fixed a bug where nonlinearity setting appeared to get lost, and + kenchis discovered further bugs in it. Oh well. + + * I removed a lot of code associated with the lower quality modes of + ReSID, and only left the 1 MHz clock routines. Analysis shows that the + filter code is a major culprit, but the digital side emulation is not + completely cheap, either. I already added some small hacks to optimize + it, and I now think about reinjecting pieces of those clocking modes + that run the analog parts with reduced accuracy. + + * I defined type4 filters based on equation of straight line. These are + characterized by parameters k and b, and the equation is + freq = k * fc. Strictly speaking, straight line is not 100 % + accurate, and a 2nd degree component would help, but based on + measurements against two of Trurl's 8580s, the maximum error + introduced using linear approximation is mere 3 %. + +2008-08-10 Antti S. Lankila + + * I ripped off Type1 definitions from the filter, and the spline.h + and PointPlotter were unnecessary and so removed. + + * I also added a bit of hardclipping in the output that seems to be + required to get Fred Gray's Break Thru. This might not occur so + strongly on all chips, so it should probably be added as a proper + tunable. For now, I just settled for a slight effect to collect + feedback. + +2008-07-15 Antti S. Lankila + + * This release is a bit slower than usual. The culprit is the changes in + voice.h where a new kinked-dac style calculation is used to simulate + the nonlinear shape of the waveform outputs. The cost of the new + calculation varies by song as I was lazy and only cached the result of + previous calculation, so speed depends on the pitch of the waveforms + and the precise waveform chosen. + + * exp() is back, but this time it is implemented as an integer + calculation according to Schraudolph's paper "A Fast, Compact + Approximation of the Exponential Function". Using near-proper exp() + simplified the distortion algorithm. I think it all sounds much better + now. + + * A new effect where I mix bp-hp and lp-bp together by their difference + to simulate a small resistor between them appears to improve SidRiders + and several other songs, largerly eliminating some types of hard + distortion sounds that do not occur on the chip. It also helped + Mechanicus. I am trying to understand where this term comes from... + +2008-07-09 Antti S. Lankila + + * I now have somewhat less arbitrary values for the distortion + tunables. They are now related to the relative signal levels in the + simulation. I'm still sorting out the particulars of the values I + ended up with ("why 128 instead of 256"). + +2008-03-02 Antti S. Lankila + + * Exposed the filter at sid.cc to callers through get_filter() + method, and fixed a few types. + +2008-02-19 Antti S. Lankila + + * For some reason ReSID code adjusted the external filter frequency + based on calculated passband, while in the real C64 the filter is + fixed to about 16 kHz. + +2008-02-06 Antti S. Lankila + + * I got interested to improve ReSID after chatting with Kevtris. He is + aiming to replicate the filter using analog hardware. He has the EE + experience that I have sorely lacked and made an infinitely valuable + contribution by telling me exactly how the distortion works. + +2004-06-11 Dag Lem + + * Version 0.16 released. (From this point forwards, read + ../resid/ChangeLog.) diff --git a/src/resid-fp/INSTALL b/src/resid-fp/INSTALL new file mode 100644 index 000000000..4573d6544 --- /dev/null +++ b/src/resid-fp/INSTALL @@ -0,0 +1,14 @@ +Unless you want to do anything fancy, just say: + +% ./configure +% make + +ReSID-FP is compiled with a C++ compiler, so if you wish to specify compiler +and compiler flags you must set CXX and CXXFLAGS, e.g.: +% CXX=g++ CXXFLAGS="-g -O" ./configure + +In addition to normal configure flags, you may specify +--disable-inline - Disable inlining of functions (for debugging/profiling) + +ReSID-FP makes no installable files. The libresid.a is linked to final +executable automatically. diff --git a/src/resid-fp/Makefile.am b/src/resid-fp/Makefile.am new file mode 100644 index 000000000..5af263229 --- /dev/null +++ b/src/resid-fp/Makefile.am @@ -0,0 +1,29 @@ +## Process this file with automake to create Makefile.in + +AR = @AR@ + +noinst_LIBRARIES = libresidfp.a + +libresidfp_a_SOURCES = sid.cc voice.cc wave.cc envelope.cc filter.cc extfilt.cc pot.cc version.cc convolve.cc $(noinst_DATA:.dat=.cc) + +BUILT_SOURCES = $(noinst_DATA:.dat=.cc) + +noinst_HEADERS = sid.h voice.h wave.h envelope.h filter.h extfilt.h pot.h + +noinst_DATA = wave6581_PST.dat wave6581_PS_.dat wave6581_P_T.dat wave6581__ST.dat wave8580_PST.dat wave8580_PS_.dat wave8580_P_T.dat wave8580__ST.dat + +noinst_SCRIPTS = samp2src.pl + +EXTRA_DIST = $(noinst_HEADERS) $(noinst_DATA) $(noinst_SCRIPTS) README.VICE convolve-sse.cc + +SUFFIXES = .dat + +.dat.cc: + $(PERL) $(srcdir)/samp2src.pl $* $< $(srcdir)/$@ + +if USE_SSE +convolve-sse.o: convolve-sse.cc + $(CXXCOMPILE) -msse -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +libresidfp_a_LIBADD = convolve-sse.o +endif diff --git a/src/resid-fp/Makefile.in b/src/resid-fp/Makefile.in new file mode 100644 index 000000000..5045f99a1 --- /dev/null +++ b/src/resid-fp/Makefile.in @@ -0,0 +1,557 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = . +DIST_COMMON = README $(am__configure_deps) $(noinst_HEADERS) \ + $(srcdir)/../../depcomp $(srcdir)/../../install-sh \ + $(srcdir)/../../missing $(srcdir)/../../mkinstalldirs \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/siddefs-fp.h.in $(top_srcdir)/configure AUTHORS \ + COPYING ChangeLog INSTALL NEWS +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs +CONFIG_CLEAN_FILES = siddefs-fp.h +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libresidfp_a_AR = $(AR) $(ARFLAGS) +@USE_SSE_TRUE@libresidfp_a_DEPENDENCIES = convolve-sse.o +am__objects_1 = wave6581_PST.$(OBJEXT) wave6581_PS_.$(OBJEXT) \ + wave6581_P_T.$(OBJEXT) wave6581__ST.$(OBJEXT) \ + wave8580_PST.$(OBJEXT) wave8580_PS_.$(OBJEXT) \ + wave8580_P_T.$(OBJEXT) wave8580__ST.$(OBJEXT) +am_libresidfp_a_OBJECTS = sid.$(OBJEXT) voice.$(OBJEXT) wave.$(OBJEXT) \ + envelope.$(OBJEXT) filter.$(OBJEXT) extfilt.$(OBJEXT) \ + pot.$(OBJEXT) version.$(OBJEXT) convolve.$(OBJEXT) \ + $(am__objects_1) +libresidfp_a_OBJECTS = $(am_libresidfp_a_OBJECTS) +SCRIPTS = $(noinst_SCRIPTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) +depcomp = $(SHELL) $(top_srcdir)/../../depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +SOURCES = $(libresidfp_a_SOURCES) +DIST_SOURCES = $(libresidfp_a_SOURCES) +DATA = $(noinst_DATA) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +HAVE_EXPF_PROTOTYPE = @HAVE_EXPF_PROTOTYPE@ +HAVE_LOGF_PROTOTYPE = @HAVE_LOGF_PROTOTYPE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RESID_HAVE_BOOL = @RESID_HAVE_BOOL@ +RESID_INLINE = @RESID_INLINE@ +RESID_USE_SSE = @RESID_USE_SSE@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_SSE_FALSE = @USE_SSE_FALSE@ +USE_SSE_TRUE = @USE_SSE_TRUE@ +VERSION = @VERSION@ +ac_ct_CXX = @ac_ct_CXX@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +noinst_LIBRARIES = libresidfp.a +libresidfp_a_SOURCES = sid.cc voice.cc wave.cc envelope.cc filter.cc extfilt.cc pot.cc version.cc convolve.cc $(noinst_DATA:.dat=.cc) +BUILT_SOURCES = $(noinst_DATA:.dat=.cc) +noinst_HEADERS = sid.h voice.h wave.h envelope.h filter.h extfilt.h pot.h +noinst_DATA = wave6581_PST.dat wave6581_PS_.dat wave6581_P_T.dat wave6581__ST.dat wave8580_PST.dat wave8580_PS_.dat wave8580_P_T.dat wave8580__ST.dat +noinst_SCRIPTS = samp2src.pl +EXTRA_DIST = $(noinst_HEADERS) $(noinst_DATA) $(noinst_SCRIPTS) README.VICE convolve-sse.cc +SUFFIXES = .dat +@USE_SSE_TRUE@libresidfp_a_LIBADD = convolve-sse.o +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .dat .cc .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +siddefs-fp.h: $(top_builddir)/config.status $(srcdir)/siddefs-fp.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libresidfp.a: $(libresidfp_a_OBJECTS) $(libresidfp_a_DEPENDENCIES) + -rm -f libresidfp.a + $(libresidfp_a_AR) libresidfp.a $(libresidfp_a_OBJECTS) $(libresidfp_a_LIBADD) + $(RANLIB) libresidfp.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/convolve.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/envelope.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extfilt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pot.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/voice.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_PST.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_PS_.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_P_T.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581__ST.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_PST.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_PS_.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_P_T.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580__ST.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkdir_p) $(distdir)/. $(distdir)/../.. + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) $(SCRIPTS) $(DATA) $(HEADERS) +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ + clean-generic clean-noinstLIBRARIES ctags dist dist-all \ + dist-bzip2 dist-gzip dist-shar dist-tarZ dist-zip distcheck \ + distclean distclean-compile distclean-generic distclean-tags \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + + +.dat.cc: + $(PERL) $(srcdir)/samp2src.pl $* $< $(srcdir)/$@ + +@USE_SSE_TRUE@convolve-sse.o: convolve-sse.cc +@USE_SSE_TRUE@ $(CXXCOMPILE) -msse -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/resid-fp/NEWS b/src/resid-fp/NEWS new file mode 100644 index 000000000..70b2d4f8e --- /dev/null +++ b/src/resid-fp/NEWS @@ -0,0 +1 @@ +See ChangeLog for information about new features. diff --git a/src/resid-fp/README b/src/resid-fp/README new file mode 100644 index 000000000..ac4f4275e --- /dev/null +++ b/src/resid-fp/README @@ -0,0 +1,79 @@ +Please refer to original ../resid/README file for general discussion what +ReSID is. + +This is ReSID-FP, a fork of ReSID that has been adapted to floating point +numbers. Some SSE assembly is used for vector convolutions when both the CPU +and compiler support it. In addition, some liberties have been taken in the +frequency region > 20 kHz which should be inaudible to humans. + +In the emulation front, several changes to the original ReSID (henceforth +classical ReSID) have been made. These changes are listed here: + +Waveforms: + +- Noise waveform control via test bit is now possible. + (Unknown: how long does it take for the noise bits to fade with test bit on?) + This is used in SounDemoN's Tamaking, Bojojoing, etc, and the patch to + implement it in ReSID is his. + +- Waveform 0, the frozen DAC, is emulated, which should make the new 8-bit + sample player routine work. + +- Envelope and waveform outputs contain approximation of the imperfect DACs + (Unknown: are there other significant effects that affect the analog waveform + before it goes into filter, which should be modelled?) + +- I changed voice DC offsets around for 6581 to better match my R4AR 3789. + +Envelope: + +- Performance work at envelope. Validation pending, should ensure that the new + code behaves 100% identically to the old one. + +Mixer: + +- Experimentally, a subtle negative offset is injected into the mixer through + ext-in pin. This part seems, however, physically incorrect and is likely + removed in the future. (The coupling capacitor external to the chip must + eliminate any DC offset, and the ext-in circuit inside the chip has nothing + that could generate offsets. In the meantime, this fix still helps 8580 + Netherworld to play more correctly.) + +- I removed the mixer_DC very subtle effect on 6581, as it already has 10x + more offsets elsewhere. + +Filter: + +- 6581 filter output contains approximation of the distortion effect +- 8580 filter output has bp flipped in phase with the other outputs +- 6581 resonance is slightly boosted. Potentially 8580 resonance needs to be + slightly stronger as well, as many songs show a bit more "punch" on the real + chip and one way to get more of that is increasing resonance. 10-20 % + increment is a practical maximum. + +The upshot of all this is that for i386/x86-64 hardware, ReSID-FP's more +complicated algorithms may not seem any more expensive than the original ReSID. +For high-quality modes, it is virtually certain that ReSID-FP is actually +faster. + +Meanwhile, emulation quality should be improved. If there are bugs, I'd like +to know about them. If the filter sounds wrong, I might be able to improve it, +too. + +Here are some problematic songs, to get a feel for what's left to do: + +- Markus Mueller: Mechanicus + * the distorted guitar effect is too distorted, but don't know how/why. + +- Galway: Wizball + * the initial lead punches through with too much distortion. The "toggle" + between the muffled and more intense sound is too hard, even if similar + things do occur on the chip. + +Undoubtedly, many more such examples will be found. However, samplings and such +are really valueable only if they can be made on a chip that I have modelled +for ReSID-FP. In practice I want to know about badly-playing chips, but might +conclude that it actually plays alright. At any event, information about sound +issues is welcome. + +alankila@bel.fi diff --git a/src/resid-fp/README.VICE b/src/resid-fp/README.VICE new file mode 100644 index 000000000..02072ce9e --- /dev/null +++ b/src/resid-fp/README.VICE @@ -0,0 +1,14 @@ +This version of reSID has been modified for use with VICE. It is based on the +work contained in the resid/ directory, with duplicate files removed. All +classes have been renamed with suffix FP to avoid link-time clashes with the +other RESID implementation. + +These files reuse some define terms also defined by resid. You should not mix +resid/* and resid-fp/* files in one compile unit, or the results are probably +invalid. + +In particular, libtool is not used to build the library, and there +might be some workarounds for various substandard compilers. + +Please get the original version if you want to use reSID in your own +project. diff --git a/src/resid-fp/aclocal.m4 b/src/resid-fp/aclocal.m4 new file mode 100644 index 000000000..aef181a6d --- /dev/null +++ b/src/resid-fp/aclocal.m4 @@ -0,0 +1,850 @@ +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.9.6])]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 7 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. +# +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/src/resid-fp/configure b/src/resid-fp/configure new file mode 100644 index 000000000..35a9c8f7d --- /dev/null +++ b/src/resid-fp/configure @@ -0,0 +1,5955 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="sid.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +CYGPATH_W +PACKAGE +VERSION +ACLOCAL +AUTOCONF +AUTOMAKE +AUTOHEADER +MAKEINFO +install_sh +STRIP +INSTALL_STRIP_PROGRAM +mkdir_p +AWK +SET_MAKE +am__leading_dot +AMTAR +am__tar +am__untar +RESID_INLINE +CXX +CXXFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CXX +EXEEXT +OBJEXT +DEPDIR +am__include +am__quote +AMDEP_TRUE +AMDEP_FALSE +AMDEPBACKSLASH +CXXDEPMODE +am__fastdepCXX_TRUE +am__fastdepCXX_FALSE +AR +RANLIB +PERL +CXXCPP +GREP +EGREP +USE_SSE_TRUE +USE_SSE_FALSE +RESID_HAVE_BOOL +RESID_USE_SSE +HAVE_LOGF_PROTOTYPE +HAVE_EXPF_PROTOTYPE +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CXX +CXXFLAGS +LDFLAGS +LIBS +CPPFLAGS +CCC +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-inline enable inlining of functions default=yes + --enable-sse enable the use of SSE default=yes + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + +Some influential environment variables: + CXX C++ compiler command + CXXFLAGS C++ compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +am__api_version="1.9" +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm -f conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } +set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + SET_MAKE= +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=resid + VERSION=0.16vice + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +LTVERSION=5:0:0 + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +# Check whether --enable-inline was given. +if test "${enable_inline+set}" = set; then + enableval=$enable_inline; +fi + +# Check whether --enable-sse was given. +if test "${enable_sse+set}" = set; then + enableval=$enable_sse; +fi + + +if test "$enable_inline" != no; then + RESID_INLINE=inline +else + RESID_INLINE= +fi + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C++ compiler default output file name" >&5 +echo $ECHO_N "checking for C++ compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C++ compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C++ compiler works" >&5 +echo $ECHO_N "checking whether the C++ compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +{ echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CXX" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +if test x"$enable_sse" != "xno"; then + if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 -msse" + { echo "$as_me:$LINENO: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo $ECHO_N "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works... $ECHO_C" >&6; } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + MSSE="-msse" + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + MSSE="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + fi +else + MSSE="" +fi + +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions" + { echo "$as_me:$LINENO: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo $ECHO_N "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works... $ECHO_C" >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + NO_EXCEPTIONS="-fno-exceptions" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + NO_EXCEPTIONS="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi +fi + +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions $NO_EXCEPTIONS -fno-pic" + { echo "$as_me:$LINENO: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo $ECHO_N "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works... $ECHO_C" >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + NO_PIC="-fno-pic" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + NO_PIC="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi +fi + +CXXFLAGS="-g -Wall -O2 $MSSE $NO_EXCEPTIONS $NO_PIC" +if test x"$MSSE" = "x-msse"; then + { echo "$as_me:$LINENO: checking if the xmmintrin.h include can be used" >&5 +echo $ECHO_N "checking if the xmmintrin.h include can be used... $ECHO_C" >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + MSSE="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS="-g -Wall -O2 $NO_EXCEPTIONS $NO_PIC" +fi + +# Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar" +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +# Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_PERL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $PERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +PERL=$ac_cv_path_PERL +if test -n "$PERL"; then + { echo "$as_me:$LINENO: result: $PERL" >&5 +echo "${ECHO_T}$PERL" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + + + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ echo "$as_me:$LINENO: result: $CXXCPP" >&5 +echo "${ECHO_T}$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking for int" >&5 +echo $ECHO_N "checking for int... $ECHO_C" >&6; } +if test "${ac_cv_type_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef int ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_int=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_int=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5 +echo "${ECHO_T}$ac_cv_type_int" >&6; } + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ echo "$as_me:$LINENO: checking size of int" >&5 +echo $ECHO_N "checking size of int... $ECHO_C" >&6; } +if test "${ac_cv_sizeof_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_int=$ac_lo;; +'') if test "$ac_cv_type_int" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_int=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } +static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (ac__type_sizeof_))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%ld\n", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%lu\n", i); + } + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_int=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_int" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_int=0 + fi +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 +echo "${ECHO_T}$ac_cv_sizeof_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + + +if test $ac_cv_sizeof_int -lt 4; then + { { echo "$as_me:$LINENO: error: only 32 bit or better CPUs are supported" >&5 +echo "$as_me: error: only 32 bit or better CPUs are supported" >&2;} + { (exit 1); exit 1; }; } +fi + +{ echo "$as_me:$LINENO: checking for working bool" >&5 +echo $ECHO_N "checking for working bool... $ECHO_C" >&6; } +if test "${ac_cv_cxx_bool+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + +bool flag; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_cxx_bool=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_cxx_bool=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_bool" >&5 +echo "${ECHO_T}$ac_cv_cxx_bool" >&6; } + +if test $ac_cv_cxx_bool = no; then + RESID_HAVE_BOOL=0 +else + RESID_HAVE_BOOL=1 +fi + +if test x"$MSSE" = "x-msse"; then + RESID_USE_SSE=1 + + +if true; then + USE_SSE_TRUE= + USE_SSE_FALSE='#' +else + USE_SSE_TRUE='#' + USE_SSE_FALSE= +fi + +else + RESID_USE_SSE=0 + + +if false; then + USE_SSE_TRUE= + USE_SSE_FALSE='#' +else + USE_SSE_TRUE='#' + USE_SSE_FALSE= +fi + +fi + + + + + + + +for ac_func in logf expf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +{ echo "$as_me:$LINENO: checking if the logf prototype is present" >&5 +echo $ECHO_N "checking if the logf prototype is present... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include +int +main () +{ +printf("%d",logf); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + HAVE_LOGF_PROTOTYPE=1 + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + HAVE_LOGF_PROTOTYPE=0 + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ echo "$as_me:$LINENO: checking if the expf prototype is present" >&5 +echo $ECHO_N "checking if the expf prototype is present... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include +int +main () +{ +printf("%d",expf); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + HAVE_EXPF_PROTOTYPE=1 + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + HAVE_EXPF_PROTOTYPE=0 + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + +ac_config_files="$ac_config_files Makefile siddefs-fp.h" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${USE_SSE_TRUE}" && test -z "${USE_SSE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${USE_SSE_TRUE}" && test -z "${USE_SSE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "siddefs-fp.h") CONFIG_FILES="$CONFIG_FILES siddefs-fp.h" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +CYGPATH_W!$CYGPATH_W$ac_delim +PACKAGE!$PACKAGE$ac_delim +VERSION!$VERSION$ac_delim +ACLOCAL!$ACLOCAL$ac_delim +AUTOCONF!$AUTOCONF$ac_delim +AUTOMAKE!$AUTOMAKE$ac_delim +AUTOHEADER!$AUTOHEADER$ac_delim +MAKEINFO!$MAKEINFO$ac_delim +install_sh!$install_sh$ac_delim +STRIP!$STRIP$ac_delim +INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim +mkdir_p!$mkdir_p$ac_delim +AWK!$AWK$ac_delim +SET_MAKE!$SET_MAKE$ac_delim +am__leading_dot!$am__leading_dot$ac_delim +AMTAR!$AMTAR$ac_delim +am__tar!$am__tar$ac_delim +am__untar!$am__untar$ac_delim +RESID_INLINE!$RESID_INLINE$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +DEPDIR!$DEPDIR$ac_delim +am__include!$am__include$ac_delim +am__quote!$am__quote$ac_delim +AMDEP_TRUE!$AMDEP_TRUE$ac_delim +AMDEP_FALSE!$AMDEP_FALSE$ac_delim +AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim +CXXDEPMODE!$CXXDEPMODE$ac_delim +am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim +am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim +AR!$AR$ac_delim +RANLIB!$RANLIB$ac_delim +PERL!$PERL$ac_delim +CXXCPP!$CXXCPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +USE_SSE_TRUE!$USE_SSE_TRUE$ac_delim +USE_SSE_FALSE!$USE_SSE_FALSE$ac_delim +RESID_HAVE_BOOL!$RESID_HAVE_BOOL$ac_delim +RESID_USE_SSE!$RESID_USE_SSE$ac_delim +HAVE_LOGF_PROTOTYPE!$HAVE_LOGF_PROTOTYPE$ac_delim +HAVE_EXPF_PROTOTYPE!$HAVE_EXPF_PROTOTYPE$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 89; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :C $CONFIG_COMMANDS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + + + :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 +echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/src/resid-fp/configure.in b/src/resid-fp/configure.in new file mode 100644 index 000000000..f4b3b5731 --- /dev/null +++ b/src/resid-fp/configure.in @@ -0,0 +1,166 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(sid.h) + +dnl Use Automake +AM_INIT_AUTOMAKE(resid, 0.16vice) +LTVERSION=5:0:0 + +dnl Use C++ for tests. +AC_LANG_CPLUSPLUS + +dnl Enable inlining. +AC_ARG_ENABLE(inline, +[ --enable-inline enable inlining of functions [default=yes]]) +AC_ARG_ENABLE(sse, +[ --enable-sse enable the use of SSE [default=yes]]) + +if test "$enable_inline" != no; then + RESID_INLINE=inline +else + RESID_INLINE= +fi + +AC_SUBST(RESID_INLINE) + +dnl Checks for programs. +AC_PROG_CXX + +dnl Set CXXFLAGS for g++. Use -msse if supported. +if test x"$enable_sse" != "xno"; then + if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 -msse" + AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) + AC_TRY_COMPILE([], + [int test;], + [ AC_MSG_RESULT(yes) + MSSE="-msse" + ], + [ AC_MSG_RESULT(no) + MSSE="" + ]) + fi + fi +else + MSSE="" +fi + +dnl Set CXXFLAGS for g++. Use -fno-exceptions if supported. +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions" + AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) + AC_TRY_COMPILE([], + [int test;], + [ AC_MSG_RESULT(yes) + NO_EXCEPTIONS="-fno-exceptions" ], + [ AC_MSG_RESULT(no) + NO_EXCEPTIONS="" + ]) + fi +fi + +dnl Set CXXFLAGS for g++. Use -fno-pic if supported. +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions $NO_EXCEPTIONS -fno-pic" + AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) + AC_TRY_COMPILE([], + [int test;], + [ AC_MSG_RESULT(yes) + NO_PIC="-fno-pic" ], + [ AC_MSG_RESULT(no) + NO_PIC="" + ]) + fi +fi + +CXXFLAGS="-g -Wall -O2 $MSSE $NO_EXCEPTIONS $NO_PIC" +if test x"$MSSE" = "x-msse"; then + AC_MSG_CHECKING([if the xmmintrin.h include can be used]) + AC_TRY_COMPILE([#include ], + [int test;], + [ AC_MSG_RESULT(yes) + ], + [ AC_MSG_RESULT(no) + MSSE="" + ]) + CXXFLAGS="-g -Wall -O2 $NO_EXCEPTIONS $NO_PIC" +fi + +AC_CHECK_PROG(AR, ar, ar, ar) +AC_PROG_RANLIB +AC_PATH_PROG(PERL, perl) + +dnl Libtool + +dnl AC_DISABLE_SHARED +dnl AM_PROG_LIBTOOL +dnl AC_SUBST(LIBTOOL_DEPS) +dnl AC_SUBST(LTVERSION) + +dnl Checks for libraries. + +dnl Checks for header files. + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_SIZEOF(int, 4) + +if test $ac_cv_sizeof_int -lt 4; then + AC_MSG_ERROR([only 32 bit or better CPUs are supported]) +fi + +AC_CACHE_CHECK([for working bool], ac_cv_cxx_bool, +[AC_TRY_COMPILE(, +[ +bool flag; +], +ac_cv_cxx_bool=yes, ac_cv_cxx_bool=no)]) + +if test $ac_cv_cxx_bool = no; then + RESID_HAVE_BOOL=0 +else + RESID_HAVE_BOOL=1 +fi + +if test x"$MSSE" = "x-msse"; then + RESID_USE_SSE=1 + AM_CONDITIONAL(USE_SSE, true) +else + RESID_USE_SSE=0 + AM_CONDITIONAL(USE_SSE, false) +fi + +AC_SUBST(RESID_HAVE_BOOL) +AC_SUBST(RESID_USE_SSE) + +dnl Checks for library functions. + +AC_CHECK_FUNCS(logf expf) + +AC_MSG_CHECKING([if the logf prototype is present]) +AC_TRY_COMPILE([#include + #include ], + [printf("%d",logf);], + [ AC_MSG_RESULT(yes) + HAVE_LOGF_PROTOTYPE=1 + ], + [ AC_MSG_RESULT(no) + HAVE_LOGF_PROTOTYPE=0 + ]) + +AC_MSG_CHECKING([if the expf prototype is present]) +AC_TRY_COMPILE([#include + #include ], + [printf("%d",expf);], + [ AC_MSG_RESULT(yes) + HAVE_EXPF_PROTOTYPE=1 + ], + [ AC_MSG_RESULT(no) + HAVE_EXPF_PROTOTYPE=0 + ]) + +AC_SUBST(HAVE_LOGF_PROTOTYPE) +AC_SUBST(HAVE_EXPF_PROTOTYPE) + +AC_OUTPUT(Makefile siddefs-fp.h) diff --git a/src/resid-fp/convolve-sse.cc b/src/resid-fp/convolve-sse.cc new file mode 100644 index 000000000..daf3979f2 --- /dev/null +++ b/src/resid-fp/convolve-sse.cc @@ -0,0 +1,76 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +#include "sid.h" + +#if (RESID_USE_SSE==1) + +#include + +float convolve_sse(const float *a, const float *b, int n) +{ + float out = 0.f; + __m128 out4 = { 0, 0, 0, 0 }; + + /* examine if we can use aligned loads on both pointers */ + int diff = (int) (a - b) & 0xf; + /* long cast is no-op for x86-32, but x86-64 gcc needs 64 bit intermediate + * to convince compiler we mean this. */ + unsigned int a_align = (unsigned int) (uintptr_t) a & 0xf; + + /* advance if necessary. We can't let n fall < 0, so no while (n --). */ + while (n > 0 && a_align != 0 && a_align != 16) { + out += (*(a ++)) * (*(b ++)); + --n; + a_align += 4; + } + + int n4 = n / 4; + if (diff == 0) { + for (int i = 0; i < n4; i ++) { + out4 = _mm_add_ps(out4, _mm_mul_ps(_mm_load_ps(a), _mm_load_ps(b))); + a += 4; + b += 4; + } + } else { + /* XXX loadu is 4x slower than load, at least. We could at 4x memory + * use prepare versions of b aligned for any a alignment. We could + * also issue aligned loads and shuffle the halves at each iteration. + * Initial results indicate only very small improvements. */ + for (int i = 0; i < n4; i ++) { + out4 = _mm_add_ps(out4, _mm_mul_ps(_mm_load_ps(a), _mm_loadu_ps(b))); + a += 4; + b += 4; + } + } + + out4 = _mm_add_ps(_mm_movehl_ps(out4, out4), out4); + out4 = _mm_add_ss(_mm_shuffle_ps(out4, out4, 1), out4); + float out_tmp; + _mm_store_ss(&out_tmp, out4); + out += out_tmp; + + n &= 3; + + while (n --) + out += (*(a ++)) * (*(b ++)); + + return out; +} +#endif diff --git a/src/resid-fp/convolve.cc b/src/resid-fp/convolve.cc new file mode 100644 index 000000000..b028ace86 --- /dev/null +++ b/src/resid-fp/convolve.cc @@ -0,0 +1,27 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +float convolve(const float *a, const float *b, int n) +{ + float out = 0.f; + while (n --) + out += (*(a ++)) * (*(b ++)); + return out; +} + diff --git a/src/resid-fp/envelope.cc b/src/resid-fp/envelope.cc new file mode 100644 index 000000000..5417adc43 --- /dev/null +++ b/src/resid-fp/envelope.cc @@ -0,0 +1,254 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __ENVELOPE_CC__ +#include "envelope.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +EnvelopeGeneratorFP::EnvelopeGeneratorFP() +{ + reset(); +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void EnvelopeGeneratorFP::reset() +{ + envelope_counter = 0; + + attack = 0; + decay = 0; + sustain = 0; + release = 0; + + gate = 0; + + rate_counter = 0; + exponential_counter = 0; + exponential_counter_period = 1; + + state = RELEASE; + rate_period = rate_counter_period[release]; + hold_zero = true; +} + + +// Rate counter periods are calculated from the Envelope Rates table in +// the Programmer's Reference Guide. The rate counter period is the number of +// cycles between each increment of the envelope counter. +// The rates have been verified by sampling ENV3. +// +// The rate counter is a 16 bit register which is incremented each cycle. +// When the counter reaches a specific comparison value, the envelope counter +// is incremented (attack) or decremented (decay/release) and the +// counter is zeroed. +// +// NB! Sampling ENV3 shows that the calculated values are not exact. +// It may seem like most calculated values have been rounded (.5 is rounded +// down) and 1 has beed added to the result. A possible explanation for this +// is that the SID designers have used the calculated values directly +// as rate counter comparison values, not considering a one cycle delay to +// zero the counter. This would yield an actual period of comparison value + 1. +// +// The time of the first envelope count can not be exactly controlled, except +// possibly by resetting the chip. Because of this we cannot do cycle exact +// sampling and must devise another method to calculate the rate counter +// periods. +// +// The exact rate counter periods can be determined e.g. by counting the number +// of cycles from envelope level 1 to envelope level 129, and dividing the +// number of cycles by 128. CIA1 timer A and B in linked mode can perform +// the cycle count. This is the method used to find the rates below. +// +// To avoid the ADSR delay bug, sampling of ENV3 should be done using +// sustain = release = 0. This ensures that the attack state will not lower +// the current rate counter period. +// +// The ENV3 sampling code below yields a maximum timing error of 14 cycles. +// lda #$01 +// l1: cmp $d41c +// bne l1 +// ... +// lda #$ff +// l2: cmp $d41c +// bne l2 +// +// This yields a maximum error for the calculated rate period of 14/128 cycles. +// The described method is thus sufficient for exact calculation of the rate +// periods. +// +reg16 EnvelopeGeneratorFP::rate_counter_period[] = { + 9, // 2ms*1.0MHz/256 = 7.81 + 32, // 8ms*1.0MHz/256 = 31.25 + 63, // 16ms*1.0MHz/256 = 62.50 + 95, // 24ms*1.0MHz/256 = 93.75 + 149, // 38ms*1.0MHz/256 = 148.44 + 220, // 56ms*1.0MHz/256 = 218.75 + 267, // 68ms*1.0MHz/256 = 265.63 + 313, // 80ms*1.0MHz/256 = 312.50 + 392, // 100ms*1.0MHz/256 = 390.63 + 977, // 250ms*1.0MHz/256 = 976.56 + 1954, // 500ms*1.0MHz/256 = 1953.13 + 3126, // 800ms*1.0MHz/256 = 3125.00 + 3907, // 1 s*1.0MHz/256 = 3906.25 + 11720, // 3 s*1.0MHz/256 = 11718.75 + 19532, // 5 s*1.0MHz/256 = 19531.25 + 31251 // 8 s*1.0MHz/256 = 31250.00 +}; + + +// For decay and release, the clock to the envelope counter is sequentially +// divided by 1, 2, 4, 8, 16, 30, 1 to create a piece-wise linear approximation +// of an exponential. The exponential counter period is loaded at the envelope +// counter values 255, 93, 54, 26, 14, 6, 0. The period can be different for the +// same envelope counter value, depending on whether the envelope has been +// rising (attack -> release) or sinking (decay/release). +// +// Since it is not possible to reset the rate counter (the test bit has no +// influence on the envelope generator whatsoever) a method must be devised to +// do cycle exact sampling of ENV3 to do the investigation. This is possible +// with knowledge of the rate period for A=0, found above. +// +// The CPU can be synchronized with ENV3 by first synchronizing with the rate +// counter by setting A=0 and wait in a carefully timed loop for the envelope +// counter _not_ to change for 9 cycles. We can then wait for a specific value +// of ENV3 with another timed loop to fully synchronize with ENV3. +// +// At the first period when an exponential counter period larger than one +// is used (decay or relase), one extra cycle is spent before the envelope is +// decremented. The envelope output is then delayed one cycle until the state +// is changed to attack. Now one cycle less will be spent before the envelope +// is incremented, and the situation is normalized. +// The delay is probably caused by the comparison with the exponential counter, +// and does not seem to affect the rate counter. This has been verified by +// timing 256 consecutive complete envelopes with A = D = R = 1, S = 0, using +// CIA1 timer A and B in linked mode. If the rate counter is not affected the +// period of each complete envelope is +// (255 + 162*1 + 39*2 + 28*4 + 12*8 + 8*16 + 6*30)*32 = 756*32 = 32352 +// which corresponds exactly to the timed value divided by the number of +// complete envelopes. +// NB! This one cycle delay is not modeled. + + +// From the sustain levels it follows that both the low and high 4 bits of the +// envelope counter are compared to the 4-bit sustain value. +// This has been verified by sampling ENV3. +// +reg8 EnvelopeGeneratorFP::sustain_level[] = { + 0x00, + 0x11, + 0x22, + 0x33, + 0x44, + 0x55, + 0x66, + 0x77, + 0x88, + 0x99, + 0xaa, + 0xbb, + 0xcc, + 0xdd, + 0xee, + 0xff, +}; + + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void EnvelopeGeneratorFP::writeCONTROL_REG(reg8 control) +{ + reg8 gate_next = control & 0x01; + + // The rate counter is never reset, thus there will be a delay before the + // envelope counter starts counting up (attack) or down (release). + + // Gate bit on: Start attack, decay, sustain. + if (!gate && gate_next) { + state = ATTACK; + update_rate_period(rate_counter_period[attack]); + + // Switching to attack state unlocks the zero freeze. + hold_zero = false; + } + // Gate bit off: Start release. + else if (gate && !gate_next) { + state = RELEASE; + update_rate_period(rate_counter_period[release]); + } + + gate = gate_next; +} + +void EnvelopeGeneratorFP::writeATTACK_DECAY(reg8 attack_decay) +{ + attack = (attack_decay >> 4) & 0x0f; + decay = attack_decay & 0x0f; + if (state == ATTACK) { + update_rate_period(rate_counter_period[attack]); + } + else if (state == DECAY_SUSTAIN) { + update_rate_period(rate_counter_period[decay]); + } +} + +void EnvelopeGeneratorFP::writeSUSTAIN_RELEASE(reg8 sustain_release) +{ + sustain = (sustain_release >> 4) & 0x0f; + release = sustain_release & 0x0f; + if (state == RELEASE) { + update_rate_period(rate_counter_period[release]); + } +} + +reg8 EnvelopeGeneratorFP::readENV() +{ + return output(); +} + +void EnvelopeGeneratorFP::update_rate_period(reg16 newperiod) +{ + rate_period = newperiod; + + /* The ADSR counter is XOR shift register with 0x7fff unique values. + * If the rate_period is adjusted to a value already seen in this cycle, + * the register will wrap around. This is known as the ADSR delay bug. + * + * To simplify the hot path calculation, we simulate this through observing + * that we add the 0x7fff cycle delay by changing the rate_counter variable + * directly. This takes care of the 99 % common case. However, playroutine + * could make multiple consequtive rate_period adjustments, in which case we + * need to cancel the previous adjustment. */ + + /* if the new period exeecds 0x7fff, we need to wrap */ + if (rate_period - rate_counter > 0x7fff) + rate_counter += 0x7fff; + + /* simulate 0x7fff wraparound, if the period-to-be-written + * is less than the current value. */ + if (rate_period <= rate_counter) + rate_counter -= 0x7fff; + + /* at this point it should be impossible for + * rate_counter >= rate_period. If it is, there is a bug... */ +} diff --git a/src/resid-fp/envelope.h b/src/resid-fp/envelope.h new file mode 100644 index 000000000..556e71a47 --- /dev/null +++ b/src/resid-fp/envelope.h @@ -0,0 +1,174 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#ifndef __ENVELOPE_H__ +#define __ENVELOPE_H__ + +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// A 15 bit counter is used to implement the envelope rates, in effect +// dividing the clock to the envelope counter by the currently selected rate +// period. +// In addition, another counter is used to implement the exponential envelope +// decay, in effect further dividing the clock to the envelope counter. +// The period of this counter is set to 1, 2, 4, 8, 16, 30 at the envelope +// counter values 255, 93, 54, 26, 14, 6, respectively. +// ---------------------------------------------------------------------------- +class EnvelopeGeneratorFP +{ +public: + EnvelopeGeneratorFP(); + + enum State { ATTACK, DECAY_SUSTAIN, RELEASE }; + + RESID_INLINE void clock(); + void reset(); + + void writeCONTROL_REG(reg8); + void writeATTACK_DECAY(reg8); + void writeSUSTAIN_RELEASE(reg8); + reg8 readENV(); + + // 8-bit envelope output. + RESID_INLINE reg8 output(); + +protected: + void update_rate_period(reg16 period); + + int rate_counter; + int rate_period; + reg8 exponential_counter; + reg8 exponential_counter_period; + reg8 envelope_counter; + bool hold_zero; + + reg4 attack; + reg4 decay; + reg4 sustain; + reg4 release; + + reg8 gate; + + State state; + + // Lookup table to convert from attack, decay, or release value to rate + // counter period. + static reg16 rate_counter_period[]; + + // The 16 selectable sustain levels. + static reg8 sustain_level[]; + +friend class SIDFP; +}; + + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +void EnvelopeGeneratorFP::clock() +{ + if (++ rate_counter != rate_period) + return; + + rate_counter = 0; + + // The first envelope step in the attack state also resets the exponential + // counter. This has been verified by sampling ENV3. + // + if (state == ATTACK || ++exponential_counter == exponential_counter_period) + { + exponential_counter = 0; + + // Check whether the envelope counter is frozen at zero. + if (hold_zero) { + return; + } + + switch (state) { + case ATTACK: + // The envelope counter can flip from 0xff to 0x00 by changing state to + // release, then to attack. The envelope counter is then frozen at + // zero; to unlock this situation the state must be changed to release, + // then to attack. This has been verified by sampling ENV3. + // + ++envelope_counter &= 0xff; + if (envelope_counter == 0xff) { + state = DECAY_SUSTAIN; + update_rate_period(rate_counter_period[decay]); + } + break; + case DECAY_SUSTAIN: + if (envelope_counter != sustain_level[sustain]) { + --envelope_counter; + } + break; + case RELEASE: + // The envelope counter can flip from 0x00 to 0xff by changing state to + // attack, then to release. The envelope counter will then continue + // counting down in the release state. + // This has been verified by sampling ENV3. + // NB! The operation below requires two's complement integer. + // + --envelope_counter &= 0xff; + break; + } + + // Check for change of exponential counter period. + switch (envelope_counter) { + case 0xff: + exponential_counter_period = 1; + break; + case 0x5d: + exponential_counter_period = 2; + break; + case 0x36: + exponential_counter_period = 4; + break; + case 0x1a: + exponential_counter_period = 8; + break; + case 0x0e: + exponential_counter_period = 16; + break; + case 0x06: + exponential_counter_period = 30; + break; + case 0x00: + exponential_counter_period = 1; + + // When the envelope counter is changed to zero, it is frozen at zero. + // This has been verified by sampling ENV3. + hold_zero = true; + break; + } + } +} + +// ---------------------------------------------------------------------------- +// Read the envelope generator output. +// ---------------------------------------------------------------------------- +RESID_INLINE +reg8 EnvelopeGeneratorFP::output() +{ + return envelope_counter; +} + +#endif // not __ENVELOPE_H__ diff --git a/src/resid-fp/extfilt.cc b/src/resid-fp/extfilt.cc new file mode 100644 index 000000000..777a23ee3 --- /dev/null +++ b/src/resid-fp/extfilt.cc @@ -0,0 +1,94 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __EXTFILT_CC__ +#include "extfilt.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +ExternalFilterFP::ExternalFilterFP() +{ + reset(); + enable_filter(true); + set_chip_model(MOS6581FP); + set_clock_frequency(1e6f); + set_sampling_parameter(15915.6f); +} + + +// ---------------------------------------------------------------------------- +// Enable filter. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::enable_filter(bool enable) +{ + enabled = enable; +} + +// ---------------------------------------------------------------------------- +// Setup of the external filter sampling parameters. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::set_clock_frequency(float clock) +{ + clock_frequency = clock; + _set_sampling_parameter(); +} + +void ExternalFilterFP::set_sampling_parameter(float freq) +{ + pass_frequency = freq; + _set_sampling_parameter(); +} + +void ExternalFilterFP::_set_sampling_parameter() +{ + // Low-pass: R = 10kOhm, C = 1000pF; w0l = 1/RC = 1/(1e4*1e-9) = 100000 + // High-pass: R = 1kOhm, C = 10uF; w0h = 1/RC = 1/(1e3*1e-5) = 100 + w0hp = 100.f / clock_frequency; + w0lp = pass_frequency * 2.f * M_PI_f / clock_frequency; +} + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::set_chip_model(chip_model model) +{ + if (model == MOS6581FP) { + // Approximate the DC output level to be removed if the external + // filter is turned off. (0x800 - wave_zero + voice DC) * maxenv * voices + // - extin offset... + mixer_DC = (-0x600 + 0x800) * 0xff * 3 - 0x20000; + } + else { + // No DC offsets in the MOS8580. + mixer_DC = 0; + } +} + + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::reset() +{ + // State of filter. + Vlp = 0; + Vhp = 0; + Vo = 0; +} diff --git a/src/resid-fp/extfilt.h b/src/resid-fp/extfilt.h new file mode 100644 index 000000000..b0e04d3b8 --- /dev/null +++ b/src/resid-fp/extfilt.h @@ -0,0 +1,120 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#ifndef __EXTFILT_H__ +#define __EXTFILT_H__ + +#include + +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// The audio output stage in a Commodore 64 consists of two STC networks, +// a low-pass filter with 3-dB frequency 16kHz followed by a high-pass +// filter with 3-dB frequency 16Hz (the latter provided an audio equipment +// input impedance of 1kOhm). +// The STC networks are connected with a BJT supposedly meant to act as +// a unity gain buffer, which is not really how it works. A more elaborate +// model would include the BJT, however DC circuit analysis yields BJT +// base-emitter and emitter-base impedances sufficiently low to produce +// additional low-pass and high-pass 3dB-frequencies in the order of hundreds +// of kHz. This calls for a sampling frequency of several MHz, which is far +// too high for practical use. +// ---------------------------------------------------------------------------- +class ExternalFilterFP +{ +public: + ExternalFilterFP(); + + void enable_filter(bool enable); + void set_sampling_parameter(float pass_freq); + void set_chip_model(chip_model model); + void set_clock_frequency(float); + + RESID_INLINE void clock(float Vi); + void reset(); + + // Audio output (20 bits). + RESID_INLINE float output(); + +private: + void _set_sampling_parameter(); + void nuke_denormals(); + + // Filter enabled. + bool enabled; + + // Maximum mixer DC offset. + float mixer_DC; + + // Relevant clocks + float clock_frequency, pass_frequency; + + // State of filters. + float Vlp; // lowpass + float Vhp; // highpass + float Vo; + + // Cutoff frequencies. + float w0lp; + float w0hp; + +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +void ExternalFilterFP::clock(float Vi) +{ + // This is handy for testing. + if (! enabled) { + // Remove maximum DC level since there is no filter to do it. + Vlp = Vhp = 0.f; + Vo = Vi - mixer_DC; + return; + } + + float dVlp = w0lp * (Vi - Vlp); + float dVhp = w0hp * (Vlp - Vhp); + Vo = Vlp - Vhp; + Vlp += dVlp; + Vhp += dVhp; +} + +// ---------------------------------------------------------------------------- +// Audio output (19.5 bits). +// ---------------------------------------------------------------------------- +RESID_INLINE +float ExternalFilterFP::output() +{ + return Vo; +} + +RESID_INLINE +void ExternalFilterFP::nuke_denormals() +{ + if (Vhp > -1e-12f && Vhp < 1e-12f) + Vhp = 0; + if (Vlp > -1e-12f && Vlp < 1e-12f) + Vlp = 0; +} + +#endif // not __EXTFILT_H__ diff --git a/src/resid-fp/filter.cc b/src/resid-fp/filter.cc new file mode 100644 index 000000000..c327fadec --- /dev/null +++ b/src/resid-fp/filter.cc @@ -0,0 +1,194 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- +// Filter distortion code written by Antti S. Lankila 2007 - 2008. + +#define __FILTER_CC__ +#include "filter.h" +#include "sid.h" + +#ifndef HAVE_LOGF_PROTOTYPE +extern float logf(float val); +#endif + +#ifndef HAVE_EXPF_PROTOTYPE +extern float expf(float val); +#endif + +#ifndef HAVE_LOGF +float logf(float val) +{ + return (float)log((double)val); +} +#endif + +#ifndef HAVE_EXPF +float expf(float val) +{ + return (float)exp((double)val); +} +#endif + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +FilterFP::FilterFP() +{ + model = (chip_model) 0; // neither 6581/8580; init time only + enable_filter(true); + /* approximate; sid.cc calls us when set_sampling_parameters() occurs. */ + set_clock_frequency(1e6f); + /* these parameters are a work-in-progress. */ + set_distortion_properties(2.5e-3f, 1536.f, 1e-4f); + /* sound similar to alankila6581r4ar3789 */ + set_type3_properties(1.40e6f, 1.47e8f, 1.0059f, 1.55e4f); + /* sound similar to trurl8580r5_3691 */ + set_type4_properties(6.55f, 20.f); + reset(); + set_chip_model(MOS6581FP); +} + + +// ---------------------------------------------------------------------------- +// Enable filter. +// ---------------------------------------------------------------------------- +void FilterFP::enable_filter(bool enable) +{ + enabled = enable; +} + + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void FilterFP::set_chip_model(chip_model model) +{ + this->model = model; + set_Q(); + set_w0(); +} + +/* dist_CT eliminates 1/x at hot spot */ +void FilterFP::set_clock_frequency(float clock) { + clock_frequency = clock; + calculate_helpers(); +} + +void FilterFP::set_distortion_properties(float r, float p, float cft) +{ + distortion_rate = r; + distortion_point = p; + /* baseresistance is used to determine material resistivity later */ + distortion_cf_threshold = cft; + calculate_helpers(); +} + +void FilterFP::set_type4_properties(float k, float b) +{ + type4_k = k; + type4_b = b; +} + +void FilterFP::set_type3_properties(float br, float o, float s, float mfr) +{ + type3_baseresistance = br; + type3_offset = o; + type3_steepness = -logf(s); /* s^x to e^(x*ln(s)), 1/e^x == e^-x. */ + type3_minimumfetresistance = mfr; +} + +void FilterFP::calculate_helpers() +{ + if (clock_frequency != 0.f) + distortion_CT = 1.f / (sidcaps_6581 * clock_frequency); + set_w0(); +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void FilterFP::reset() +{ + fc = 0; + res = filt = voice3off = hp_bp_lp = 0; + vol = 0; + volf = Vhp = Vbp = Vlp = 0; + set_w0(); + set_Q(); +} + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void FilterFP::writeFC_LO(reg8 fc_lo) +{ + fc = (fc & 0x7f8) | (fc_lo & 0x007); + set_w0(); +} + +void FilterFP::writeFC_HI(reg8 fc_hi) +{ + fc = ((fc_hi << 3) & 0x7f8) | (fc & 0x007); + set_w0(); +} + +void FilterFP::writeRES_FILT(reg8 res_filt) +{ + res = (res_filt >> 4) & 0x0f; + set_Q(); + + filt = res_filt & 0x0f; +} + +void FilterFP::writeMODE_VOL(reg8 mode_vol) +{ + voice3off = mode_vol & 0x80; + + hp_bp_lp = (mode_vol >> 4) & 0x07; + + vol = mode_vol & 0x0f; + volf = (float) vol / 15.f; +} + +// Set filter cutoff frequency. +void FilterFP::set_w0() +{ + if (model == MOS6581FP) { + /* div once by extra kinkiness because I fitted the type3 eq with that variant. */ + float type3_fc_kink = SIDFP::kinked_dac(fc, kinkiness, 11) / kinkiness; + type3_fc_kink_exp = type3_offset * expf(type3_fc_kink * type3_steepness); + if (distortion_rate != 0.f) { + type3_fc_distortion_offset_hp = (distortion_point - type3_fc_kink) * (0.5f) / distortion_rate; + type3_fc_distortion_offset_bp = type3_fc_distortion_offset_hp; + } + else { + type3_fc_distortion_offset_bp = 9e9f; + type3_fc_distortion_offset_hp = 9e9f; + } + } + if (model == MOS8580FP) { + type4_w0_cache = type4_w0(); + } +} + +// Set filter resonance. +void FilterFP::set_Q() +{ + float Q = res / 15.f; + _1_div_Q = 1.f / (0.707f + Q * 1.5f); +} diff --git a/src/resid-fp/filter.h b/src/resid-fp/filter.h new file mode 100644 index 000000000..13e6aa67e --- /dev/null +++ b/src/resid-fp/filter.h @@ -0,0 +1,383 @@ +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- +// Filter distortion code written by Antti S. Lankila 2007 - 2008. + +#ifndef __FILTER_H__ +#define __FILTER_H__ + +#include +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// The SID filter is modeled with a two-integrator-loop biquadratic filter, +// which has been confirmed by Bob Yannes to be the actual circuit used in +// the SID chip. +// +// Measurements show that excellent emulation of the SID filter is achieved, +// except when high resonance is combined with high sustain levels. +// In this case the SID op-amps are performing less than ideally and are +// causing some peculiar behavior of the SID filter. This however seems to +// have more effect on the overall amplitude than on the color of the sound. +// +// The theory for the filter circuit can be found in "Microelectric Circuits" +// by Adel S. Sedra and Kenneth C. Smith. +// The circuit is modeled based on the explanation found there except that +// an additional inverter is used in the feedback from the bandpass output, +// allowing the summer op-amp to operate in single-ended mode. This yields +// inverted filter outputs with levels independent of Q, which corresponds with +// the results obtained from a real SID. +// +// We have been able to model the summer and the two integrators of the circuit +// to form components of an IIR filter. +// Vhp is the output of the summer, Vbp is the output of the first integrator, +// and Vlp is the output of the second integrator in the filter circuit. +// +// According to Bob Yannes, the active stages of the SID filter are not really +// op-amps. Rather, simple NMOS inverters are used. By biasing an inverter +// into its region of quasi-linear operation using a feedback resistor from +// input to output, a MOS inverter can be made to act like an op-amp for +// small signals centered around the switching threshold. +// +// Qualified guesses at SID filter schematics are depicted below. +// +// SID filter +// ---------- +// +// ----------------------------------------------- +// | | +// | ---Rq-- | +// | | | | +// | --------------|--R-----[A>--|--R-----[A>--| +// | | | | +// vi -----R1-- | | | +// +// vhp vbp vlp +// +// +// vi - input voltage +// vhp - highpass output +// vbp - bandpass output +// vlp - lowpass output +// [A> - op-amp +// R1 - summer resistor +// Rq - resistor array controlling resonance (4 resistors) +// R - NMOS FET voltage controlled resistor controlling cutoff frequency +// Rs - shunt resitor +// C - capacitor +// +// +// +// SID integrator +// -------------- +// +// V+ +// +// | +// | +// -----| +// | | +// | ||-- +// -|| +// ---C--- ||-> +// | | | +// |---Rs-----------|---- vo +// | | +// | ||-- +// vi ---- -----|------------|| +// | ^ | ||-> +// |___| | | +// ----- | | +// | | | +// |---R2-- | +// | +// R1 V- +// | +// | +// +// Vw +// +// ---------------------------------------------------------------------------- +class FilterFP +{ +public: + FilterFP(); + + void enable_filter(bool enable); + void set_chip_model(chip_model model); + void set_distortion_properties(float, float, float); + void set_type3_properties(float, float, float, float); + void set_type4_properties(float, float); + void set_clock_frequency(float); + + RESID_INLINE + float clock(float voice1, float voice2, float voice3, + float ext_in); + void reset(); + + // Write registers. + void writeFC_LO(reg8); + void writeFC_HI(reg8); + void writeRES_FILT(reg8); + void writeMODE_VOL(reg8); + +private: + void set_Q(); + void set_w0(); + float type3_w0(const float source, const float offset); + float type4_w0(); + void calculate_helpers(); + void nuke_denormals(); + + // Filter enabled. + bool enabled; + + // 6581/8580 filter model (XXX: we should specialize in separate classes) + chip_model model; + + // Filter cutoff frequency. + reg12 fc; + + // Filter resonance. + reg8 res; + + // Selects which inputs to route through filter. + reg8 filt; + + // Switch voice 3 off. + reg8 voice3off; + + // Highpass, bandpass, and lowpass filter modes. + reg8 hp_bp_lp; + + // Output master volume. + reg4 vol; + float volf; /* avoid integer-to-float conversion at output */ + + // clock + float clock_frequency; + + /* Distortion params for Type3 */ + float distortion_rate, distortion_point, distortion_cf_threshold; + + /* Type3 params. */ + float type3_baseresistance, type3_offset, type3_steepness, type3_minimumfetresistance; + + /* Type4 params */ + float type4_k, type4_b; + + // State of filter. + float Vhp, Vbp, Vlp; + + /* Resonance/Distortion/Type3/Type4 helpers. */ + float type4_w0_cache, _1_div_Q, type3_fc_kink_exp, distortion_CT, + type3_fc_distortion_offset_bp, type3_fc_distortion_offset_hp; + +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// Inline functions. +// The following functions are defined inline because they are called every +// time a sample is calculated. +// ---------------------------------------------------------------------------- + +/* kinkiness of DAC: + * some chips have more, some less. We should make this tunable. */ +const float kinkiness = 0.966f; +const float sidcaps_6581 = 470e-12f; +const float outputleveldifference_lp_bp = 1.4f; +const float outputleveldifference_bp_hp = 1.2f; + +RESID_INLINE +static float fastexp(float val) { + typedef union { + int i; + float f; + } conv; + + conv tmp; + + /* single precision fp has 1 + 8 + 23 bits, exponent bias is 127. + * It therefore follows that we need to shift left by 23 bits, and to + * calculate exp(x) instead of pow(2, x) we divide the power by ln(2). */ + const float a = (1 << 23) / M_LN2_f; + /* The other factor corrects for the exponent bias so that 2^0 = 1. */ + const float b = (1 << 23) * 127; + /* According to "A Fast, Compact Approximation of the Exponential Function" + * by Nicol N. Schraudolph, 60801.48 yields the minimum RMS error for the + * piecewise-linear approximation when using doubles (20 bits residual). + * We have 23 bits, so we scale this value by 8. */ + const float c = 60801.48f * 8.f + 0.5f; + + /* Parenthesis are important: C standard disallows folding subtraction. + * Unfortunately GCC appears to generate a write to memory rather than + * handle this conversion entirely in registers. */ + tmp.i = (int)(a * val + (b - c)); + return tmp.f; +} + +RESID_INLINE +float FilterFP::type3_w0(const float source, const float distoffset) +{ + /* The distortion appears to be the result of MOSFET entering saturation + * mode. The conductance of a FET is proportional to: + * + * ohmic = 2 * (Vgs - Vt) * Vds - Vds^2 + * saturation = (Vgs - Vt)^2 + * + * The FET switches to saturation mode when Vgs - Vt < Vds. + * + * In the circuit, the Vgs is mixed with the Vds signal, which gives + * (Vgs + Vds) / 2 as the gate voltage. Doing the substitutions we get: + * + * ohmic = 2 * ((Vgs + Vds) / 2 - Vt) * Vds - Vds^2 = (Vgs - Vt) * Vds + * saturation = ((Vgs + Vds) / 2 - Vt)^2 + * + * Therefore: once the Vds crosses a threshold given by the gate and + * threshold FET conductance begins to increase faster. The exact shape + * for this effect is a parabola. + * + * The scaling term here tries to match the FC control level with + * the signal level in simulation. On the chip, the FC control is + * biased by forcing its highest DAC bit in the 1 position, thus + * limiting the electrical range to half. Therefore one can guess that + * the real FC range is half of the full voice range. + * + * On the simulation, FC goes to 2047 and the voices to 4095 * 255. + * If the FC control was intact, then the scaling factor would be + * 1/512. (Simulation voices are 512 times "louder" intrinsically.) + * As the real chip's FC has reduced range, the scaling required to + * match levels is 1/256. */ + + float fetresistance = type3_fc_kink_exp; + if (source > distoffset) { + const float dist = source - distoffset; + fetresistance *= fastexp(dist * type3_steepness * distortion_rate); + } + const float dynamic_resistance = type3_minimumfetresistance + fetresistance; + + /* 2 parallel resistors */ + const float _1_div_resistance = (type3_baseresistance + dynamic_resistance) / (type3_baseresistance * dynamic_resistance); + /* 1.f / (clock * caps * resistance) */ + return distortion_CT * _1_div_resistance; +} + +RESID_INLINE +float FilterFP::type4_w0() +{ + const float freq = type4_k * fc + type4_b; + return 2.f * M_PI_f * freq / clock_frequency; +} + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +float FilterFP::clock(float voice1, + float voice2, + float voice3, + float ext_in) +{ + /* Avoid denormal numbers by using small offsets from 0 */ + float Vi = 0.f, Vnf = 0.f, Vf = 0.f; + + // Route voices into or around filter. + ((filt & 1) ? Vi : Vnf) += voice1; + ((filt & 2) ? Vi : Vnf) += voice2; + // NB! Voice 3 is not silenced by voice3off if it is routed through + // the filter. + if (filt & 4) + Vi += voice3; + else if (! voice3off) + Vnf += voice3; + ((filt & 8) ? Vi : Vnf) += ext_in; + + if (! enabled) + return (Vnf - Vi) * volf; + + if (hp_bp_lp & 1) + Vf += Vlp; + if (hp_bp_lp & 2) + Vf += Vbp; + if (hp_bp_lp & 4) + Vf += Vhp; + + if (model == MOS6581FP) { + float diff1, diff2; + + Vhp = Vbp * _1_div_Q * (1.f/outputleveldifference_bp_hp) - Vlp * (1.f/outputleveldifference_bp_hp) - Vi * 0.5f; + + /* the input summer mixing, or something like it... */ + diff1 = (Vlp - Vbp) * distortion_cf_threshold; + diff2 = (Vhp - Vbp) * distortion_cf_threshold; + Vlp -= diff1; + Vbp += diff1; + Vbp += diff2; + Vhp -= diff2; + + /* Model output strip mixing. Doing it now that HP state + * variable modifying still makes some difference. + * (Phase error, though.) */ + if (hp_bp_lp & 1) + Vlp += (Vf + Vnf - Vlp) * distortion_cf_threshold; + if (hp_bp_lp & 2) + Vbp += (Vf + Vnf - Vbp) * distortion_cf_threshold; + if (hp_bp_lp & 4) + Vhp += (Vf + Vnf - Vhp) * distortion_cf_threshold; + + /* Simulating the exponential VCR that the FET block is... */ + Vlp -= Vbp * type3_w0(Vbp, type3_fc_distortion_offset_bp); + Vbp -= Vhp * type3_w0(Vhp, type3_fc_distortion_offset_hp) * outputleveldifference_bp_hp; + + /* Tuned based on Fred Gray's Break Thru. It is probably not a hard + * discontinuity but a saturation effect... */ + if (Vnf > 3.2e6f) + Vnf = 3.2e6f; + + Vf += Vnf + Vlp * (outputleveldifference_lp_bp - 1.f); + } else { + /* On the 8580, BP appears mixed in phase with the rest. */ + Vhp = -Vbp * _1_div_Q - Vlp - Vi; + Vlp += Vbp * type4_w0_cache; + Vbp += Vhp * type4_w0_cache; + + Vf += Vnf; + } + + return Vf * volf; +} + +RESID_INLINE +void FilterFP::nuke_denormals() +{ + /* We could use the flush-to-zero flag or denormals-are-zero on systems + * where compiling with -msse and -mfpmath=sse is acceptable. Since this + * doesn't include general VICE builds, we do this instead. */ + if (Vbp > -1e-12f && Vbp < 1e-12f) + Vbp = 0; + if (Vlp > -1e-12f && Vlp < 1e-12f) + Vlp = 0; +} + +#endif // not __FILTER_H__ diff --git a/src/resid-fp/pot.cc b/src/resid-fp/pot.cc new file mode 100644 index 000000000..4cd85a5c3 --- /dev/null +++ b/src/resid-fp/pot.cc @@ -0,0 +1,26 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "pot.h" + +reg8 PotentiometerFP::readPOT() +{ + // NB! Not modeled. + return 0xff; +} diff --git a/src/resid-fp/pot.h b/src/resid-fp/pot.h new file mode 100644 index 000000000..e1deeabda --- /dev/null +++ b/src/resid-fp/pot.h @@ -0,0 +1,31 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#ifndef __POT_H__ +#define __POT_H__ + +#include "siddefs-fp.h" + +class PotentiometerFP +{ +public: + reg8 readPOT(); +}; + +#endif diff --git a/src/resid-fp/samp2src.pl b/src/resid-fp/samp2src.pl new file mode 100644 index 000000000..fc6398382 --- /dev/null +++ b/src/resid-fp/samp2src.pl @@ -0,0 +1,65 @@ +#! /usr/bin/perl -w +# --------------------------------------------------------------------------- +# This file is part of reSID, a MOS6581 SID emulator engine. +# Copyright (C) 2004 Dag Lem +# +# 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 +# --------------------------------------------------------------------------- + +use strict; + +die("Usage: samp2src name data-in src-out\n") unless @ARGV == 3; +my ($name, $in, $out) = @ARGV; + +open(F, "<$in") or die($!); +local $/ = undef; +my $data = ; +close(F) or die($!); + +open(F, ">$out") or die($!); + +print F <<\EOF; +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +EOF + +print F "#include \"wave.h\"\n\nreg8 WaveformGeneratorFP::$name\[\] =\n{\n"; + +for (my $i = 0; $i < length($data); $i += 8) { + print F sprintf("/* 0x%03x: */ ", $i), map(sprintf(" 0x%02x,", $_), unpack("C*", substr($data, $i, 8))), "\n"; +} + +print F "};\n"; + +close(F) or die($!); + +exit(0); diff --git a/src/resid-fp/sid.cc b/src/resid-fp/sid.cc new file mode 100644 index 000000000..eda01ab2f --- /dev/null +++ b/src/resid-fp/sid.cc @@ -0,0 +1,944 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "sid.h" +#include +#include + +extern float convolve(const float *a, const float *b, int n); +extern float convolve_sse(const float *a, const float *b, int n); + +enum host_cpu_feature { + HOST_CPU_MMX=1, HOST_CPU_SSE=2, HOST_CPU_SSE2=4, HOST_CPU_SSE3=8 +}; + +/* This code is appropriate for 32-bit and 64-bit x86 CPUs. */ +#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) + +struct cpu_x86_regs_s { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; +}; +typedef struct cpu_x86_regs_s cpu_x86_regs_t; + +static cpu_x86_regs_t get_cpuid_regs(unsigned int index) +{ + cpu_x86_regs_t retval; + +#if defined(_MSC_VER) /* MSVC assembly */ + __asm { + mov eax, [index] + cpuid + mov [retval.eax], eax + mov [retval.ebx], ebx + mov [retval.ecx], ecx + mov [retval.edx], edx + } +#else /* GNU assembly */ + asm("movl %1, %%eax; cpuid; movl %%eax, %0;" + : "=m" (retval.eax) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); + asm("movl %1, %%eax; cpuid; movl %%ebx, %0;" + : "=m" (retval.ebx) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); + asm("movl %1, %%eax; cpuid; movl %%ecx, %0;" + : "=m" (retval.ecx) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); + asm("movl %1, %%eax; cpuid; movl %%edx, %0;" + : "=m" (retval.edx) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); +#endif + + return retval; +} + +static int host_cpu_features_by_cpuid(void) +{ + cpu_x86_regs_t regs = get_cpuid_regs(1); + + int features = 0; + if (regs.edx & (1 << 23)) + features |= HOST_CPU_MMX; + if (regs.edx & (1 << 25)) + features |= HOST_CPU_SSE; + if (regs.edx & (1 << 26)) + features |= HOST_CPU_SSE2; + if (regs.ecx & (1 << 0)) + features |= HOST_CPU_SSE3; + + return features; +} + +static int host_cpu_features(void) +{ + static int features = 0; + static int features_detected = 0; +/* 32-bit only */ +#if defined(__i386__) || (defined(_MSC_VER) && defined(_WIN32)) + unsigned long temp1, temp2; +#endif + + if (features_detected) + return features; + features_detected = 1; + +#if defined(_MSC_VER) && defined(_WIN32) /* MSVC compatible assembly appropriate for 32-bit Windows */ + /* see if we are dealing with a cpu that has the cpuid instruction */ + __asm { + pushf + pop eax + mov [temp1], eax + xor eax, 0x200000 + push eax + popf + pushf + pop eax + mov [temp2], eax + push [temp1] + popf + } +#endif +#if defined(__i386__) /* GNU assembly */ + asm("pushfl; popl %%eax; movl %%eax, %0; xorl $0x200000, %%eax; pushl %%eax; popfl; pushfl; popl %%eax; movl %%eax, %1; pushl %0; popfl " + : "=r" (temp1), + "=r" (temp2) + : + : "eax"); +#endif +#if defined(__i386__) || (defined(_MSC_VER) && defined(_WIN32)) + temp1 &= 0x200000; + temp2 &= 0x200000; + if (temp1 == temp2) { + /* no cpuid support, so we can't test for SSE availability -> false */ + return 0; + } +#endif + + /* find the highest supported cpuid function, returned in %eax */ + if (get_cpuid_regs(0).eax < 1) { + /* no cpuid 1 function, we can't test for features -> no features */ + return 0; + } + + features = host_cpu_features_by_cpuid(); + return features; +} + +#else /* !__x86_64__ && !__i386__ && !_MSC_VER */ +static int host_cpu_features(void) +{ + return 0; +} +#endif + +float SIDFP::kinked_dac(const int x, const float nonlinearity, const int max) +{ + float value = 0.f; + + int bit = 1; + float weight = 1.f; + const float dir = 2.0f * nonlinearity; + for (int i = 0; i < max; i ++) { + if (x & bit) + value += weight; + bit <<= 1; + weight *= dir; + } + + return value / (weight / nonlinearity) * (1 << max); +} + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +SIDFP::SIDFP() +{ +#if (RESID_USE_SSE==1) + can_use_sse = (host_cpu_features() & HOST_CPU_SSE) != 0; +#else + can_use_sse = false; +#endif + + // Initialize pointers. + sample = 0; + fir = 0; + + voice[0].set_sync_source(&voice[2]); + voice[1].set_sync_source(&voice[0]); + voice[2].set_sync_source(&voice[1]); + + set_sampling_parameters(985248, SAMPLE_INTERPOLATE, 44100); + + bus_value = 0; + bus_value_ttl = 0; + + input(0); +} + + +// ---------------------------------------------------------------------------- +// Destructor. +// ---------------------------------------------------------------------------- +SIDFP::~SIDFP() +{ + delete[] sample; + delete[] fir; +} + + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void SIDFP::set_chip_model(chip_model model) +{ + for (int i = 0; i < 3; i++) { + voice[i].set_chip_model(model); + } + + filter.set_chip_model(model); + extfilt.set_chip_model(model); +} + +/* nonlinear DAC support, set 1 for 8580 / no effect, about 0.96 otherwise */ +void SIDFP::set_voice_nonlinearity(float nl) +{ + for (int i = 0; i < 3; i++) { + voice[i].set_nonlinearity(nl); + } +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void SIDFP::reset() +{ + for (int i = 0; i < 3; i++) { + voice[i].reset(); + } + filter.reset(); + extfilt.reset(); + + bus_value = 0; + bus_value_ttl = 0; +} + + +// ---------------------------------------------------------------------------- +// Write 16-bit sample to audio input. +// NB! The caller is responsible for keeping the value within 16 bits. +// Note that to mix in an external audio signal, the signal should be +// resampled to 1MHz first to avoid sampling noise. +// ---------------------------------------------------------------------------- +void SIDFP::input(int sample) +{ + // Voice outputs are 20 bits. Scale up to match three voices in order + // to facilitate simulation of the MOS8580 "digi boost" hardware hack. + ext_in = (float) ( (sample << 4) * 3 ); +} + +float SIDFP::output() +{ + const float range = 1 << 15; + return extfilt.output() / (4095.f * 255.f * 3.f * 1.5f / range); +} + +// ---------------------------------------------------------------------------- +// Read registers. +// +// Reading a write only register returns the last byte written to any SID +// register. The individual bits in this value start to fade down towards +// zero after a few cycles. All bits reach zero within approximately +// $2000 - $4000 cycles. +// It has been claimed that this fading happens in an orderly fashion, however +// sampling of write only registers reveals that this is not the case. +// NB! This is not correctly modeled. +// The actual use of write only registers has largely been made in the belief +// that all SID registers are readable. To support this belief the read +// would have to be done immediately after a write to the same register +// (remember that an intermediate write to another register would yield that +// value instead). With this in mind we return the last value written to +// any SID register for $2000 cycles without modeling the bit fading. +// ---------------------------------------------------------------------------- +reg8 SIDFP::read(reg8 offset) +{ + switch (offset) { + case 0x19: + return potx.readPOT(); + case 0x1a: + return poty.readPOT(); + case 0x1b: + return voice[2].wave.readOSC(); + case 0x1c: + return voice[2].envelope.readENV(); + default: + return bus_value; + } +} + + +// ---------------------------------------------------------------------------- +// Write registers. +// ---------------------------------------------------------------------------- +void SIDFP::write(reg8 offset, reg8 value) +{ + bus_value = value; + bus_value_ttl = 0x4000; + + switch (offset) { + case 0x00: + voice[0].wave.writeFREQ_LO(value); + break; + case 0x01: + voice[0].wave.writeFREQ_HI(value); + break; + case 0x02: + voice[0].wave.writePW_LO(value); + break; + case 0x03: + voice[0].wave.writePW_HI(value); + break; + case 0x04: + voice[0].writeCONTROL_REG(value); + break; + case 0x05: + voice[0].envelope.writeATTACK_DECAY(value); + break; + case 0x06: + voice[0].envelope.writeSUSTAIN_RELEASE(value); + break; + case 0x07: + voice[1].wave.writeFREQ_LO(value); + break; + case 0x08: + voice[1].wave.writeFREQ_HI(value); + break; + case 0x09: + voice[1].wave.writePW_LO(value); + break; + case 0x0a: + voice[1].wave.writePW_HI(value); + break; + case 0x0b: + voice[1].writeCONTROL_REG(value); + break; + case 0x0c: + voice[1].envelope.writeATTACK_DECAY(value); + break; + case 0x0d: + voice[1].envelope.writeSUSTAIN_RELEASE(value); + break; + case 0x0e: + voice[2].wave.writeFREQ_LO(value); + break; + case 0x0f: + voice[2].wave.writeFREQ_HI(value); + break; + case 0x10: + voice[2].wave.writePW_LO(value); + break; + case 0x11: + voice[2].wave.writePW_HI(value); + break; + case 0x12: + voice[2].writeCONTROL_REG(value); + break; + case 0x13: + voice[2].envelope.writeATTACK_DECAY(value); + break; + case 0x14: + voice[2].envelope.writeSUSTAIN_RELEASE(value); + break; + case 0x15: + filter.writeFC_LO(value); + break; + case 0x16: + filter.writeFC_HI(value); + break; + case 0x17: + filter.writeRES_FILT(value); + break; + case 0x18: + filter.writeMODE_VOL(value); + break; + default: + break; + } +} + + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +SIDFP::State::State() +{ + int i; + + for (i = 0; i < 0x20; i++) { + sid_register[i] = 0; + } + + bus_value = 0; + bus_value_ttl = 0; + + for (i = 0; i < 3; i++) { + accumulator[i] = 0; + shift_register[i] = 0x7ffff8; + rate_counter[i] = 0; + rate_counter_period[i] = 9; + exponential_counter[i] = 0; + exponential_counter_period[i] = 1; + envelope_counter[i] = 0; + envelope_state[i] = EnvelopeGeneratorFP::RELEASE; + hold_zero[i] = true; + } +} + + +// ---------------------------------------------------------------------------- +// Read state. +// ---------------------------------------------------------------------------- +SIDFP::State SIDFP::read_state() +{ + State state; + int i, j; + + for (i = 0, j = 0; i < 3; i++, j += 7) { + WaveformGeneratorFP& wave = voice[i].wave; + EnvelopeGeneratorFP& envelope = voice[i].envelope; + state.sid_register[j + 0] = wave.freq & 0xff; + state.sid_register[j + 1] = wave.freq >> 8; + state.sid_register[j + 2] = wave.pw & 0xff; + state.sid_register[j + 3] = wave.pw >> 8; + state.sid_register[j + 4] = + (wave.waveform << 4) + | (wave.test ? 0x08 : 0) + | (wave.ring_mod ? 0x04 : 0) + | (wave.sync ? 0x02 : 0) + | (envelope.gate ? 0x01 : 0); + state.sid_register[j + 5] = (envelope.attack << 4) | envelope.decay; + state.sid_register[j + 6] = (envelope.sustain << 4) | envelope.release; + } + + state.sid_register[j++] = filter.fc & 0x007; + state.sid_register[j++] = filter.fc >> 3; + state.sid_register[j++] = (filter.res << 4) | filter.filt; + state.sid_register[j++] = + (filter.voice3off ? 0x80 : 0) + | (filter.hp_bp_lp << 4) + | filter.vol; + + // These registers are superfluous, but included for completeness. + for (; j < 0x1d; j++) { + state.sid_register[j] = read(j); + } + for (; j < 0x20; j++) { + state.sid_register[j] = 0; + } + + state.bus_value = bus_value; + state.bus_value_ttl = bus_value_ttl; + + for (i = 0; i < 3; i++) { + state.accumulator[i] = voice[i].wave.accumulator; + state.shift_register[i] = voice[i].wave.shift_register; + state.rate_counter[i] = voice[i].envelope.rate_counter; + state.rate_counter_period[i] = voice[i].envelope.rate_period; + state.exponential_counter[i] = voice[i].envelope.exponential_counter; + state.exponential_counter_period[i] = voice[i].envelope.exponential_counter_period; + state.envelope_counter[i] = voice[i].envelope.envelope_counter; + state.envelope_state[i] = voice[i].envelope.state; + state.hold_zero[i] = voice[i].envelope.hold_zero; + } + + return state; +} + + +// ---------------------------------------------------------------------------- +// Write state. +// ---------------------------------------------------------------------------- +void SIDFP::write_state(const State& state) +{ + int i; + + for (i = 0; i <= 0x18; i++) { + write(i, state.sid_register[i]); + } + + bus_value = state.bus_value; + bus_value_ttl = state.bus_value_ttl; + + for (i = 0; i < 3; i++) { + voice[i].wave.accumulator = state.accumulator[i]; + voice[i].wave.shift_register = state.shift_register[i]; + voice[i].envelope.rate_counter = state.rate_counter[i]; + voice[i].envelope.rate_period = state.rate_counter_period[i]; + voice[i].envelope.exponential_counter = state.exponential_counter[i]; + voice[i].envelope.exponential_counter_period = state.exponential_counter_period[i]; + voice[i].envelope.envelope_counter = state.envelope_counter[i]; + voice[i].envelope.state = state.envelope_state[i]; + voice[i].envelope.hold_zero = state.hold_zero[i]; + } +} + + +// ---------------------------------------------------------------------------- +// Enable filter. +// ---------------------------------------------------------------------------- +void SIDFP::enable_filter(bool enable) +{ + filter.enable_filter(enable); +} + + +// ---------------------------------------------------------------------------- +// Enable external filter. +// ---------------------------------------------------------------------------- +void SIDFP::enable_external_filter(bool enable) +{ + extfilt.enable_filter(enable); +} + + +// ---------------------------------------------------------------------------- +// I0() computes the 0th order modified Bessel function of the first kind. +// This function is originally from resample-1.5/filterkit.c by J. O. Smith. +// ---------------------------------------------------------------------------- +double SIDFP::I0(double x) +{ + // Max error acceptable in I0 could be 1e-6, which gives that 96 dB already. + // I'm overspecify these errors to get a beautiful FFT dump of the FIR. + const double I0e = 1e-10; + + double sum, u, halfx, temp; + int n; + + sum = u = n = 1; + halfx = x/2.0; + + do { + temp = halfx/n++; + u *= temp*temp; + sum += u; + } while (u >= I0e*sum); + + return sum; +} + + +// ---------------------------------------------------------------------------- +// Setting of SID sampling parameters. +// +// Use a clock freqency of 985248Hz for PAL C64, 1022730Hz for NTSC C64. +// The default end of passband frequency is pass_freq = 0.9*sample_freq/2 +// for sample frequencies up to ~ 44.1kHz, and 20kHz for higher sample +// frequencies. +// +// For resampling, the ratio between the clock frequency and the sample +// frequency is limited as follows: +// 125*clock_freq/sample_freq < 16384 +// E.g. provided a clock frequency of ~ 1MHz, the sample frequency can not +// be set lower than ~ 8kHz. A lower sample frequency would make the +// resampling code overfill its 16k sample ring buffer. +// +// The end of passband frequency is also limited: +// pass_freq <= 0.9*sample_freq/2 + +// E.g. for a 44.1kHz sampling rate the end of passband frequency is limited +// to slightly below 20kHz. This constraint ensures that the FIR table is +// not overfilled. +// ---------------------------------------------------------------------------- +bool SIDFP::set_sampling_parameters(float clock_freq, sampling_method method, + float sample_freq, float pass_freq) +{ + clock_frequency = clock_freq; + sampling = method; + + filter.set_clock_frequency(clock_freq); + extfilt.set_clock_frequency(clock_freq); + adjust_sampling_frequency(sample_freq); + + sample_offset = 0; + sample_prev = 0; + + // FIR initialization is only necessary for resampling. + if (method != SAMPLE_RESAMPLE_INTERPOLATE) + { + delete[] sample; + delete[] fir; + sample = 0; + fir = 0; + return true; + } + + const int bits = 16; + + if (pass_freq > 20000) + pass_freq = 20000; + if (2*pass_freq/sample_freq > 0.9) + pass_freq = 0.9f*sample_freq/2; + + // 16 bits -> -96dB stopband attenuation. + const double A = -20*log10(1.0/(1 << bits)); + + // For calculation of beta and N see the reference for the kaiserord + // function in the MATLAB Signal Processing Toolbox: + // http://www.mathworks.com/access/helpdesk/help/toolbox/signal/kaiserord.html + const double beta = 0.1102*(A - 8.7); + const double I0beta = I0(beta); + + double f_samples_per_cycle = sample_freq/clock_freq; + double f_cycles_per_sample = clock_freq/sample_freq; + + /* This code utilizes the fact that aliasing back to 20 kHz from + * sample_freq/2 is inaudible. This allows us to define a passband + * wider than normally. We might also consider aliasing back to pass_freq, + * but as this can be less than 20 kHz, it might become audible... */ + double aliasing_allowance = sample_freq / 2 - 20000; + if (aliasing_allowance < 0) + aliasing_allowance = 0; + + double transition_bandwidth = sample_freq/2 - pass_freq + aliasing_allowance; + { + /* Filter order according to Kaiser's paper. */ + + int N = (int) ((A - 7.95)/(2 * M_PI * 2.285 * transition_bandwidth/sample_freq) + 0.5); + N += N & 1; + + // The filter length is equal to the filter order + 1. + // The filter length must be an odd number (sinc is symmetric about x = 0). + fir_N = int(N*f_cycles_per_sample) + 1; + fir_N |= 1; + + // Check whether the sample ring buffer would overfill. + if (fir_N > RINGSIZE - 1) + return false; + + /* Error is bound by 1.234 / L^2 */ + fir_RES = (int) (sqrt(1.234 * (1 << bits)) / f_cycles_per_sample + 0.5); + } + + // Allocate memory for FIR tables. + delete[] fir; + fir = new float[fir_N*fir_RES]; + + // The cutoff frequency is midway through the transition band. + double wc = (pass_freq + transition_bandwidth/2) / sample_freq * M_PI * 2; + + // Calculate fir_RES FIR tables for linear interpolation. + for (int i = 0; i < fir_RES; i++) { + double j_offset = double(i)/fir_RES; + // Calculate FIR table. This is the sinc function, weighted by the + // Kaiser window. + for (int j = 0; j < fir_N; j ++) { + double jx = j - fir_N/2. - j_offset; + double wt = wc*jx/f_cycles_per_sample; + double temp = jx/(fir_N/2); + double Kaiser = + fabs(temp) <= 1 ? I0(beta*sqrt(1 - temp*temp))/I0beta : 0; + double sincwt = + fabs(wt) >= 1e-8 ? sin(wt)/wt : 1; + fir[i * fir_N + j] = (float) (f_samples_per_cycle*wc/M_PI*sincwt*Kaiser); + } + } + + // Allocate sample buffer. + if (!sample) { + sample = new float[RINGSIZE*2]; + } + // Clear sample buffer. + for (int j = 0; j < RINGSIZE*2; j++) { + sample[j] = 0; + } + sample_index = 0; + + return true; +} + +// ---------------------------------------------------------------------------- +// Adjustment of SID sampling frequency. +// +// In some applications, e.g. a C64 emulator, it can be desirable to +// synchronize sound with a timer source. This is supported by adjustment of +// the SID sampling frequency. +// +// NB! Adjustment of the sampling frequency may lead to noticeable shifts in +// frequency, and should only be used for interactive applications. Note also +// that any adjustment of the sampling frequency will change the +// characteristics of the resampling filter, since the filter is not rebuilt. +// ---------------------------------------------------------------------------- +void SIDFP::adjust_sampling_frequency(float sample_freq) +{ + cycles_per_sample = clock_frequency/sample_freq; +} + +void SIDFP::age_bus_value(cycle_count n) { + if (bus_value_ttl != 0) { + bus_value_ttl -= n; + if (bus_value_ttl <= 0) { + bus_value = 0; + bus_value_ttl = 0; + } + } +} + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +void SIDFP::clock() +{ + int i; + + // Clock amplitude modulators. + for (i = 0; i < 3; i++) { + voice[i].envelope.clock(); + } + + // Clock oscillators. + for (i = 0; i < 3; i++) { + voice[i].wave.clock(); + } + + // Synchronize oscillators. + for (i = 0; i < 3; i++) { + voice[i].wave.synchronize(); + } + + // Clock filter. + extfilt.clock(filter.clock(voice[0].output(), voice[1].output(), voice[2].output(), ext_in)); +} + +// ---------------------------------------------------------------------------- +// SID clocking with audio sampling. +// Fixpoint arithmetics is used. +// +// The example below shows how to clock the SID a specified amount of cycles +// while producing audio output: +// +// while (delta_t) { +// bufindex += sid.clock(delta_t, buf + bufindex, buflength - bufindex); +// write(dsp, buf, bufindex*2); +// bufindex = 0; +// } +// +// ---------------------------------------------------------------------------- +int SIDFP::clock(cycle_count& delta_t, short* buf, int n, int interleave) +{ + /* XXX I assume n is generally large enough for delta_t here... */ + age_bus_value(delta_t); + int res; + switch (sampling) { + default: + case SAMPLE_INTERPOLATE: + res = clock_interpolate(delta_t, buf, n, interleave); + break; + case SAMPLE_RESAMPLE_INTERPOLATE: + res = clock_resample_interpolate(delta_t, buf, n, interleave); + break; + } + + filter.nuke_denormals(); + extfilt.nuke_denormals(); + + return res; +} + +// ---------------------------------------------------------------------------- +// SID clocking with audio sampling - cycle based with linear sample +// interpolation. +// +// Here the chip is clocked every cycle. This yields higher quality +// sound since the samples are linearly interpolated, and since the +// external filter attenuates frequencies above 16kHz, thus reducing +// sampling noise. +// ---------------------------------------------------------------------------- +RESID_INLINE +int SIDFP::clock_interpolate(cycle_count& delta_t, short* buf, int n, + int interleave) +{ + int s = 0; + int i; + + for (;;) { + float next_sample_offset = sample_offset + cycles_per_sample; + int delta_t_sample = (int) next_sample_offset; + if (delta_t_sample > delta_t) { + break; + } + if (s >= n) { + return s; + } + for (i = 0; i < delta_t_sample - 1; i++) { + clock(); + } + if (i < delta_t_sample) { + sample_prev = output(); + clock(); + } + + delta_t -= delta_t_sample; + sample_offset = next_sample_offset - delta_t_sample; + + float sample_now = output(); + int v = (int)(sample_prev + (sample_offset * (sample_now - sample_prev))); + // Saturated arithmetics to guard against 16 bit sample overflow. + const int half = 1 << 15; + if (v >= half) { + v = half - 1; + } + else if (v < -half) { + v = -half; + } + buf[s++*interleave] = v; + sample_prev = sample_now; + } + + for (i = 0; i < delta_t - 1; i++) { + clock(); + } + if (i < delta_t) { + sample_prev = output(); + clock(); + } + sample_offset -= delta_t; + delta_t = 0; + return s; +} + +// ---------------------------------------------------------------------------- +// SID clocking with audio sampling - cycle based with audio resampling. +// +// This is the theoretically correct (and computationally intensive) audio +// sample generation. The samples are generated by resampling to the specified +// sampling frequency. The work rate is inversely proportional to the +// percentage of the bandwidth allocated to the filter transition band. +// +// This implementation is based on the paper "A Flexible Sampling-Rate +// Conversion Method", by J. O. Smith and P. Gosset, or rather on the +// expanded tutorial on the "Digital Audio Resampling Home Page": +// http://www-ccrma.stanford.edu/~jos/resample/ +// +// By building shifted FIR tables with samples according to the +// sampling frequency, this implementation dramatically reduces the +// computational effort in the filter convolutions, without any loss +// of accuracy. The filter convolutions are also vectorizable on +// current hardware. +// +// Further possible optimizations are: +// * An equiripple filter design could yield a lower filter order, see +// http://www.mwrf.com/Articles/ArticleID/7229/7229.html +// * The Convolution Theorem could be used to bring the complexity of +// convolution down from O(n*n) to O(n*log(n)) using the Fast Fourier +// Transform, see http://en.wikipedia.org/wiki/Convolution_theorem +// * Simply resampling in two steps can also yield computational +// savings, since the transition band will be wider in the first step +// and the required filter order is thus lower in this step. +// Laurent Ganier has found the optimal intermediate sampling frequency +// to be (via derivation of sum of two steps): +// 2 * pass_freq + sqrt [ 2 * pass_freq * orig_sample_freq +// * (dest_sample_freq - 2 * pass_freq) / dest_sample_freq ] +// +// NB! the result of right shifting negative numbers is really +// implementation dependent in the C++ standard. +// ---------------------------------------------------------------------------- +RESID_INLINE +int SIDFP::clock_resample_interpolate(cycle_count& delta_t, short* buf, int n, + int interleave) +{ + int s = 0; + + for (;;) { + float next_sample_offset = sample_offset + cycles_per_sample; + /* full clocks left to next sample */ + int delta_t_sample = (int) next_sample_offset; + if (delta_t_sample > delta_t || s >= n) + break; + + /* clock forward delta_t_sample samples */ + for (int i = 0; i < delta_t_sample; i++) { + clock(); + sample[sample_index] = sample[sample_index + RINGSIZE] = output(); + ++ sample_index; + sample_index &= RINGSIZE - 1; + } + delta_t -= delta_t_sample; + + /* Phase of the sample in terms of clock, [0 .. 1[. */ + sample_offset = next_sample_offset - (float) delta_t_sample; + + /* find the first of the nearest fir tables close to the phase */ + float fir_offset_rmd = sample_offset * fir_RES; + int fir_offset = (int) fir_offset_rmd; + /* [0 .. 1[ */ + fir_offset_rmd -= (float) fir_offset; + + /* find fir_N most recent samples, plus one extra in case the FIR wraps. */ + float* sample_start = sample + sample_index - fir_N + RINGSIZE - 1; + + float v1 = +#if (RESID_USE_SSE==1) + can_use_sse ? convolve_sse(sample_start, fir + fir_offset*fir_N, fir_N) : +#endif + convolve(sample_start, fir + fir_offset*fir_N, fir_N); + + // Use next FIR table, wrap around to first FIR table using + // previous sample. + if (++ fir_offset == fir_RES) { + fir_offset = 0; + ++ sample_start; + } + float v2 = +#if (RESID_USE_SSE==1) + can_use_sse ? convolve_sse(sample_start, fir + fir_offset*fir_N, fir_N) : +#endif + convolve(sample_start, fir + fir_offset*fir_N, fir_N); + + // Linear interpolation between the sinc tables yields good approximation + // for the exact value. + int v = (int) (v1 + fir_offset_rmd * (v2 - v1)); + + // Saturated arithmetics to guard against 16 bit sample overflow. + const int half = 1 << 15; + if (v >= half) { + v = half - 1; + } + else if (v < -half) { + v = -half; + } + + buf[s ++ * interleave] = v; + } + + /* clock forward delta_t samples */ + for (int i = 0; i < delta_t; i++) { + clock(); + sample[sample_index] = sample[sample_index + RINGSIZE] = output(); + ++ sample_index; + sample_index &= RINGSIZE - 1; + } + sample_offset -= (float) delta_t; + delta_t = 0; + return s; +} diff --git a/src/resid-fp/sid.h b/src/resid-fp/sid.h new file mode 100644 index 000000000..6dad2e0c4 --- /dev/null +++ b/src/resid-fp/sid.h @@ -0,0 +1,130 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#ifndef __SID_FP_H__ +#define __SID_FP_H__ + +#include "siddefs-fp.h" +#include "voice.h" +#include "filter.h" +#include "extfilt.h" +#include "pot.h" + +class SIDFP +{ +public: + SIDFP(); + ~SIDFP(); + + static float kinked_dac(const int x, const float nonlinearity, const int bits); + bool sse_enabled() { return can_use_sse; } + + void set_chip_model(chip_model model); + FilterFP& get_filter() { return filter; } + void enable_filter(bool enable); + void enable_external_filter(bool enable); + bool set_sampling_parameters(float clock_freq, sampling_method method, + float sample_freq, float pass_freq = -1); + void adjust_sampling_frequency(float sample_freq); + void set_voice_nonlinearity(float nonlinearity); + + void clock(); + int clock(cycle_count& delta_t, short* buf, int n, int interleave = 1); + void reset(); + + // Read/write registers. + reg8 read(reg8 offset); + void write(reg8 offset, reg8 value); + + // Read/write state. + class State + { + public: + State(); + + char sid_register[0x20]; + + reg8 bus_value; + cycle_count bus_value_ttl; + + reg24 accumulator[3]; + reg24 shift_register[3]; + reg16 rate_counter[3]; + reg16 rate_counter_period[3]; + reg16 exponential_counter[3]; + reg16 exponential_counter_period[3]; + reg8 envelope_counter[3]; + EnvelopeGeneratorFP::State envelope_state[3]; + bool hold_zero[3]; + }; + + State read_state(); + void write_state(const State& state); + + // 16-bit input (EXT IN). + void input(int sample); + + // output in range -32768 .. 32767, not clipped (AUDIO OUT) + float output(); + +protected: + static double I0(double x); + RESID_INLINE int clock_interpolate(cycle_count& delta_t, short* buf, int n, + int interleave); + RESID_INLINE int clock_resample_interpolate(cycle_count& delta_t, short* buf, + int n, int interleave); + RESID_INLINE void age_bus_value(cycle_count); + + VoiceFP voice[3]; + FilterFP filter; + ExternalFilterFP extfilt; + PotentiometerFP potx; + PotentiometerFP poty; + + reg8 bus_value; + cycle_count bus_value_ttl; + + float clock_frequency; + + // External audio input. + float ext_in; + + enum { RINGSIZE = 16384 }; + + // Sampling variables. + sampling_method sampling; + float cycles_per_sample; + float sample_offset; + int sample_index; + int fir_N; + int fir_RES; + + // Linear interpolation helper + float sample_prev; + + // Ring buffer with overflow for contiguous storage of RINGSIZE samples. + float* sample; + + // FIR_RES filter tables (FIR_N*FIR_RES). + float* fir; + + bool can_use_sse; +}; + +#endif // not __SID_H__ diff --git a/src/resid-fp/siddefs-fp.h b/src/resid-fp/siddefs-fp.h new file mode 100644 index 000000000..1f3f72715 --- /dev/null +++ b/src/resid-fp/siddefs-fp.h @@ -0,0 +1,88 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 1999 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#ifndef __SIDDEFS_FP_H__ +#define __SIDDEFS_FP_H__ + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#define M_PI_f 3.14159265358979323846f +#else +#define M_PI_f ((float) M_PI) +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#define M_LN2_f 0.69314718055994530942f +#else +#define M_LN2_f ((float) M_LN2) +#endif + +// Define bool, true, and false for C++ compilers that lack these keywords. +#define RESID_HAVE_BOOL 1 + +#if !RESID_HAVE_BOOL +typedef int bool; +const bool true = 1; +const bool false = 0; +#endif + +// We could have used the smallest possible data type for each SID register, +// however this would give a slower engine because of data type conversions. +// An int is assumed to be at least 32 bits (necessary in the types reg24, +// cycle_count, and sound_sample). GNU does not support 16-bit machines +// (GNU Coding Standards: Portability between CPUs), so this should be +// a valid assumption. + +typedef unsigned int reg4; +typedef unsigned int reg8; +typedef unsigned int reg12; +typedef unsigned int reg16; +typedef unsigned int reg24; + +typedef int cycle_count; + +enum chip_model { MOS6581FP=1, MOS8580FP }; + +enum sampling_method { SAMPLE_INTERPOLATE=1, SAMPLE_RESAMPLE_INTERPOLATE }; + +extern "C" +{ +#ifndef __VERSION_CC__ +extern const char* resid_version_string; +#else +const char* resid_version_string = VERSION; +#endif +} + +// Inlining on/off. +#define RESID_INLINE inline + +#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300)) +#define RESID_USE_SSE 1 +#else +#define RESID_USE_SSE 0 +#endif + +#define HAVE_LOGF +#define HAVE_EXPF +#define HAVE_LOGF_PROTOTYPE +#define HAVE_EXPF_PROTOTYPE + +#endif // not __SIDDEFS_H__ diff --git a/src/resid-fp/siddefs-fp.h.in b/src/resid-fp/siddefs-fp.h.in new file mode 100644 index 000000000..ec44b3619 --- /dev/null +++ b/src/resid-fp/siddefs-fp.h.in @@ -0,0 +1,87 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 1999 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#ifndef __SIDDEFS_FP_H__ +#define __SIDDEFS_FP_H__ + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#define M_PI_f 3.14159265358979323846f +#else +#define M_PI_f ((float) M_PI) +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#define M_LN2_f 0.69314718055994530942f +#else +#define M_LN2_f ((float) M_LN2) +#endif + +// Define bool, true, and false for C++ compilers that lack these keywords. +#define RESID_HAVE_BOOL @RESID_HAVE_BOOL@ + +#if !RESID_HAVE_BOOL +typedef int bool; +const bool true = 1; +const bool false = 0; +#endif + +// We could have used the smallest possible data type for each SID register, +// however this would give a slower engine because of data type conversions. +// An int is assumed to be at least 32 bits (necessary in the types reg24, +// cycle_count, and sound_sample). GNU does not support 16-bit machines +// (GNU Coding Standards: Portability between CPUs), so this should be +// a valid assumption. + +typedef unsigned int reg4; +typedef unsigned int reg8; +typedef unsigned int reg12; +typedef unsigned int reg16; +typedef unsigned int reg24; + +typedef int cycle_count; + +enum chip_model { MOS6581FP=1, MOS8580FP }; + +enum sampling_method { SAMPLE_INTERPOLATE=1, SAMPLE_RESAMPLE_INTERPOLATE }; + +extern "C" +{ +#ifndef __VERSION_CC__ +extern const char* resid_version_string; +#else +const char* resid_version_string = VERSION; +#endif +} + +// Inlining on/off. +#define RESID_INLINE @RESID_INLINE@ + +#define RESID_USE_SSE @RESID_USE_SSE@ + +#if @HAVE_LOGF_PROTOTYPE@ +#define HAVE_LOGF_PROTOTYPE +#endif + +#if @HAVE_EXPF_PROTOTYPE@ +#define HAVE_EXPF_PROTOTYPE +#endif + +#endif // not __SIDDEFS_H__ diff --git a/src/resid-fp/version.cc b/src/resid-fp/version.cc new file mode 100644 index 000000000..fe9d4595f --- /dev/null +++ b/src/resid-fp/version.cc @@ -0,0 +1,21 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __VERSION_CC__ +#include "siddefs-fp.h" diff --git a/src/resid-fp/voice.cc b/src/resid-fp/voice.cc new file mode 100644 index 000000000..18c36cc71 --- /dev/null +++ b/src/resid-fp/voice.cc @@ -0,0 +1,102 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __VOICE_CC__ +#include "voice.h" +#include "sid.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +VoiceFP::VoiceFP() +{ + nonlinearity = 1.f; + set_chip_model(MOS6581FP); +} + +/* Keep this at 1.f for 8580, there are no 6581-only codepaths in this file! */ +void VoiceFP::set_nonlinearity(float nl) +{ + nonlinearity = nl; + calculate_dac_tables(); +} + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void VoiceFP::set_chip_model(chip_model model) +{ + wave.set_chip_model(model); + + if (model == MOS6581FP) { + /* there is some level from each voice even if the env is down and osc + * is stopped. You can hear this by routing a voice into filter (filter + * should be kept disabled for this) as the master level changes. This + * tunable affects the volume of digis. */ + voice_DC = 0x800 * 0xff; + /* In 8580 the waveforms seem well centered, but on the 6581 there is some + * offset change as envelope grows, indicating that the waveforms are not + * perfectly centered. I estimate the value ~ 0x600 for my R4AR, and ReSID + * has used another measurement technique and got 0x380. */ + wave_zero = 0x600; + calculate_dac_tables(); + } + else { + /* 8580 is thought to be perfect, apart from small negative offset due to + * ext-in mixing, I think. */ + voice_DC = 0; + wave_zero = 0x800; + calculate_dac_tables(); + } +} + +void VoiceFP::calculate_dac_tables() +{ + int i; + for (i = 0; i < 256; i ++) + env_dac[i] = SIDFP::kinked_dac(i, nonlinearity, 8); + for (i = 0; i < 4096; i ++) + voice_dac[i] = SIDFP::kinked_dac(i, nonlinearity, 12) - wave_zero; +} + +// ---------------------------------------------------------------------------- +// Set sync source. +// ---------------------------------------------------------------------------- +void VoiceFP::set_sync_source(VoiceFP* source) +{ + wave.set_sync_source(&source->wave); +} + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void VoiceFP::writeCONTROL_REG(reg8 control) +{ + wave.writeCONTROL_REG(control); + envelope.writeCONTROL_REG(control); +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void VoiceFP::reset() +{ + wave.reset(); + envelope.reset(); +} diff --git a/src/resid-fp/voice.h b/src/resid-fp/voice.h new file mode 100644 index 000000000..3a9e3fc95 --- /dev/null +++ b/src/resid-fp/voice.h @@ -0,0 +1,73 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#ifndef __VOICE_H__ +#define __VOICE_H__ + +#include "siddefs-fp.h" +#include "wave.h" +#include "envelope.h" + +class VoiceFP +{ +public: + VoiceFP(); + + void set_chip_model(chip_model model); + void set_sync_source(VoiceFP*); + void reset(); + + void writeCONTROL_REG(reg8); + + // Amplitude modulated waveform output. + // Range [-2048*255, 2047*255]. + RESID_INLINE float output(); + + void set_nonlinearity(float nl); +protected: + void calculate_dac_tables(); + + WaveformGeneratorFP wave; + EnvelopeGeneratorFP envelope; + + // Multiplying D/A DC offset. + float voice_DC, wave_zero, nonlinearity; + + float env_dac[256]; + float voice_dac[4096]; +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// Amplitude modulated waveform output. +// Ideal range [-2048*255, 2047*255]. +// ---------------------------------------------------------------------------- + +RESID_INLINE +float VoiceFP::output() +{ + unsigned int w = wave.output(); + unsigned int e = envelope.output(); + float _w = voice_dac[w]; + float _e = env_dac[e]; + + return _w * _e + voice_DC; +} + +#endif // not __VOICE_H__ diff --git a/src/resid-fp/wave.cc b/src/resid-fp/wave.cc new file mode 100644 index 000000000..018c4e2be --- /dev/null +++ b/src/resid-fp/wave.cc @@ -0,0 +1,151 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __WAVE_CC__ +#include "wave.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +WaveformGeneratorFP::WaveformGeneratorFP() +{ + sync_source = this; + + set_chip_model(MOS6581FP); + + reset(); +} + + +// ---------------------------------------------------------------------------- +// Set sync source. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::set_sync_source(WaveformGeneratorFP* source) +{ + sync_source = source; + source->sync_dest = this; +} + + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::set_chip_model(chip_model model) +{ + if (model == MOS6581FP) { + wave__ST = wave6581__ST; + wave_P_T = wave6581_P_T; + wave_PS_ = wave6581_PS_; + wave_PST = wave6581_PST; + } + else { + wave__ST = wave8580__ST; + wave_P_T = wave8580_P_T; + wave_PS_ = wave8580_PS_; + wave_PST = wave8580_PST; + } +} + + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::writeFREQ_LO(reg8 freq_lo) +{ + freq = (freq & 0xff00) | (freq_lo & 0x00ff); +} + +void WaveformGeneratorFP::writeFREQ_HI(reg8 freq_hi) +{ + freq = ((freq_hi << 8) & 0xff00) | (freq & 0x00ff); +} + +/* The original form was (acc >> 12) >= pw, where truth value is not affected + * by the contents of the low 12 bits. Therefore the lowest bits must be zero + * in the new formulation acc >= (pw << 12). */ +void WaveformGeneratorFP::writePW_LO(reg8 pw_lo) +{ + pw = (pw & 0xf00) | (pw_lo & 0x0ff); + pw_acc_scale = pw << 12; +} + +void WaveformGeneratorFP::writePW_HI(reg8 pw_hi) +{ + pw = ((pw_hi << 8) & 0xf00) | (pw & 0x0ff); + pw_acc_scale = pw << 12; +} + +void WaveformGeneratorFP::writeCONTROL_REG(reg8 control) +{ + waveform = (control >> 4) & 0x0f; + ring_mod = control & 0x04; + sync = control & 0x02; + + reg8 test_next = control & 0x08; + + /* SounDemoN found out that test bit can be used to control the noise + * register. Hear the result in Bojojoing.sid. */ + + // testbit set. invert bit 19 and write it to bit 1 + if (test_next && !test) { + accumulator = 0; + reg24 bit19 = (shift_register >> 19) & 1; + shift_register = (shift_register & 0x7ffffd) | ((bit19^1) << 1); + noise_overwrite_delay = 200000; /* 200 ms, probably too generous? */ + } + // Test bit cleared. + // The accumulator starts counting, and the shift register is reset to + // the value 0x7ffff8. + else if (!test_next && test) { + reg24 bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1; + shift_register <<= 1; + shift_register |= bit0; + } + // clear output bits of shift register if noise and other waveforms + // are selected simultaneously + if (waveform > 8) { + shift_register &= 0x7fffff^(1<<22)^(1<<20)^(1<<16)^(1<<13)^(1<<11)^(1<<7)^(1<<4)^(1<<2); + } + + test = test_next; + + /* update noise anyway, just in case the above paths triggered */ + noise_output_cached = outputN___(); +} + +reg8 WaveformGeneratorFP::readOSC() +{ + return output() >> 4; +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::reset() +{ + accumulator = 0; + previous = 0; + shift_register = 0x7ffffc; + freq = 0; + pw = 0; + pw_acc_scale = 0; + test = 0; + writeCONTROL_REG(0); + msb_rising = false; +} diff --git a/src/resid-fp/wave.h b/src/resid-fp/wave.h new file mode 100644 index 000000000..07d229ba0 --- /dev/null +++ b/src/resid-fp/wave.h @@ -0,0 +1,457 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#ifndef __WAVE_H__ +#define __WAVE_H__ + +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// A 24 bit accumulator is the basis for waveform generation. FREQ is added to +// the lower 16 bits of the accumulator each cycle. +// The accumulator is set to zero when TEST is set, and starts counting +// when TEST is cleared. +// The noise waveform is taken from intermediate bits of a 23 bit shift +// register. This register is clocked by bit 19 of the accumulator. +// ---------------------------------------------------------------------------- +class WaveformGeneratorFP +{ +public: + WaveformGeneratorFP(); + + void set_sync_source(WaveformGeneratorFP*); + void set_chip_model(chip_model model); + + RESID_INLINE void clock(); + RESID_INLINE void synchronize(); + void reset(); + + void writeFREQ_LO(reg8); + void writeFREQ_HI(reg8); + void writePW_LO(reg8); + void writePW_HI(reg8); + void writeCONTROL_REG(reg8); + reg8 readOSC(); + + // 12-bit waveform output. + RESID_INLINE reg12 output(); + +protected: + const WaveformGeneratorFP* sync_source; + WaveformGeneratorFP* sync_dest; + + // Tell whether the accumulator MSB was set high on this cycle. + bool msb_rising; + + reg24 accumulator; + reg24 shift_register; + reg12 previous, noise_output_cached; + int noise_overwrite_delay; + + // Fout = (Fn*Fclk/16777216)Hz + reg16 freq; + // PWout = (PWn/40.95)%, also the same << 12 for direct comparison against acc + reg12 pw; reg24 pw_acc_scale; + + // The control register right-shifted 4 bits; used for output function + // table lookup. + reg8 waveform; + + // The remaining control register bits. + reg8 test; + reg8 ring_mod; + reg8 sync; + // The gate bit is handled by the EnvelopeGenerator. + + // 16 possible combinations of waveforms. + RESID_INLINE reg12 output___T(); + RESID_INLINE reg12 output__S_(); + RESID_INLINE reg12 output__ST(); + RESID_INLINE reg12 output_P__(); + RESID_INLINE reg12 output_P_T(); + RESID_INLINE reg12 output_PS_(); + RESID_INLINE reg12 output_PST(); + RESID_INLINE reg12 outputN___(); + RESID_INLINE reg12 outputN__T(); + RESID_INLINE reg12 outputN_S_(); + RESID_INLINE reg12 outputN_ST(); + RESID_INLINE reg12 outputNP__(); + RESID_INLINE reg12 outputNP_T(); + RESID_INLINE reg12 outputNPS_(); + RESID_INLINE reg12 outputNPST(); + + // Sample data for combinations of waveforms. + static reg8 wave6581__ST[]; + static reg8 wave6581_P_T[]; + static reg8 wave6581_PS_[]; + static reg8 wave6581_PST[]; + + static reg8 wave8580__ST[]; + static reg8 wave8580_P_T[]; + static reg8 wave8580_PS_[]; + static reg8 wave8580_PST[]; + + reg8* wave__ST; + reg8* wave_P_T; + reg8* wave_PS_; + reg8* wave_PST; + +friend class VoiceFP; +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +void WaveformGeneratorFP::clock() +{ + /* no digital operation if test bit is set. Only emulate analog fade. */ + if (test) { + if (noise_overwrite_delay != 0) { + if (-- noise_overwrite_delay == 0) { + shift_register |= 0x7ffffc; + noise_output_cached = outputN___(); + } + } + return; + } + + reg24 accumulator_prev = accumulator; + + // Calculate new accumulator value; + accumulator += freq; + accumulator &= 0xffffff; + + // Check whether the MSB became set high. This is used for synchronization. + msb_rising = !(accumulator_prev & 0x800000) && (accumulator & 0x800000); + + // Shift noise register once for each time accumulator bit 19 is set high. + if (!(accumulator_prev & 0x080000) && (accumulator & 0x080000)) { + reg24 bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1; + shift_register <<= 1; + // optimization: fall into the bit bucket + //shift_register &= 0x7fffff; + shift_register |= bit0; + + /* since noise changes relatively infrequently, we'll avoid the relatively + * expensive bit shuffling at output time. */ + noise_output_cached = outputN___(); + } + + // clear output bits of shift register if noise and other waveforms + // are selected simultaneously + if (waveform > 8) { + shift_register &= 0x7fffff^(1<<22)^(1<<20)^(1<<16)^(1<<13)^(1<<11)^(1<<7)^(1<<4)^(1<<2); + noise_output_cached = outputN___(); + } +} + +// ---------------------------------------------------------------------------- +// Synchronize oscillators. +// This must be done after all the oscillators have been clock()'ed since the +// oscillators operate in parallel. +// Note that the oscillators must be clocked exactly on the cycle when the +// MSB is set high for hard sync to operate correctly. See SID::clock(). +// ---------------------------------------------------------------------------- +RESID_INLINE +void WaveformGeneratorFP::synchronize() +{ + // A special case occurs when a sync source is synced itself on the same + // cycle as when its MSB is set high. In this case the destination will + // not be synced. This has been verified by sampling OSC3. + if (msb_rising && sync_dest->sync && !(sync && sync_source->msb_rising)) { + sync_dest->accumulator = 0; + } +} + + +// ---------------------------------------------------------------------------- +// Output functions. +// NB! The output from SID 8580 is delayed one cycle compared to SID 6581, +// this is not modeled. +// ---------------------------------------------------------------------------- + +// Triangle: +// The upper 12 bits of the accumulator are used. +// The MSB is used to create the falling edge of the triangle by inverting +// the lower 11 bits. The MSB is thrown away and the lower 11 bits are +// left-shifted (half the resolution, full amplitude). +// Ring modulation substitutes the MSB with MSB EOR sync_source MSB. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output___T() +{ + reg24 msb = (ring_mod ? accumulator ^ sync_source->accumulator : accumulator) + & 0x800000; + return ((msb ? ~accumulator : accumulator) >> 11) & 0xfff; +} + +// Sawtooth: +// The output is identical to the upper 12 bits of the accumulator. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output__S_() +{ + return accumulator >> 12; +} + +// Pulse: +// The upper 12 bits of the accumulator are used. +// These bits are compared to the pulse width register by a 12 bit digital +// comparator; output is either all one or all zero bits. +// NB! The output is actually delayed one cycle after the compare. +// This is not modeled. +// +// The test bit, when set to one, holds the pulse waveform output at 0xfff +// regardless of the pulse width setting. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output_P__() +{ + return (test || accumulator >= pw_acc_scale) ? 0xfff : 0x000; +} + +// Noise: +// The noise output is taken from intermediate bits of a 23-bit shift register +// which is clocked by bit 19 of the accumulator. +// NB! The output is actually delayed 2 cycles after bit 19 is set high. +// This is not modeled. +// +// Operation: Calculate EOR result, shift register, set bit 0 = result. +// +// ----------------------->--------------------- +// | | +// ----EOR---- | +// | | | +// 2 2 2 1 1 1 1 1 1 1 1 1 1 | +// Register bits: 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 <--- +// | | | | | | | | +// OSC3 bits : 7 6 5 4 3 2 1 0 +// +// Since waveform output is 12 bits the output is left-shifted 4 times. +// +RESID_INLINE +reg12 WaveformGeneratorFP::outputN___() +{ + return + ((shift_register & 0x400000) >> 11) | + ((shift_register & 0x100000) >> 10) | + ((shift_register & 0x010000) >> 7) | + ((shift_register & 0x002000) >> 5) | + ((shift_register & 0x000800) >> 4) | + ((shift_register & 0x000080) >> 1) | + ((shift_register & 0x000010) << 1) | + ((shift_register & 0x000004) << 2); +} + +// Combined waveforms: +// By combining waveforms, the bits of each waveform are effectively short +// circuited. A zero bit in one waveform will result in a zero output bit +// (thus the infamous claim that the waveforms are AND'ed). +// However, a zero bit in one waveform will also affect the neighboring bits +// in the output. The reason for this has not been determined. +// +// Example: +// +// 1 1 +// Bit # 1 0 9 8 7 6 5 4 3 2 1 0 +// ----------------------- +// Sawtooth 0 0 0 1 1 1 1 1 1 0 0 0 +// +// Triangle 0 0 1 1 1 1 1 1 0 0 0 0 +// +// AND 0 0 0 1 1 1 1 1 0 0 0 0 +// +// Output 0 0 0 0 1 1 1 0 0 0 0 0 +// +// +// This behavior would be quite difficult to model exactly, since the SID +// in this case does not act as a digital state machine. Tests show that minor +// (1 bit) differences can actually occur in the output from otherwise +// identical samples from OSC3 when waveforms are combined. To further +// complicate the situation the output changes slightly with time (more +// neighboring bits are successively set) when the 12-bit waveform +// registers are kept unchanged. +// +// It is probably possible to come up with a valid model for the +// behavior, however this would be far too slow for practical use since it +// would have to be based on the mutual influence of individual bits. +// +// The output is instead approximated by using the upper bits of the +// accumulator as an index to look up the combined output in a table +// containing actual combined waveform samples from OSC3. +// These samples are 8 bit, so 4 bits of waveform resolution is lost. +// All OSC3 samples are taken with FREQ=0x1000, adding a 1 to the upper 12 +// bits of the accumulator each cycle for a sample period of 4096 cycles. +// +// Sawtooth+Triangle: +// The sawtooth output is used to look up an OSC3 sample. +// +// Pulse+Triangle: +// The triangle output is right-shifted and used to look up an OSC3 sample. +// The sample is output if the pulse output is on. +// The reason for using the triangle output as the index is to handle ring +// modulation. Only the first half of the sample is used, which should be OK +// since the triangle waveform has half the resolution of the accumulator. +// +// Pulse+Sawtooth: +// The sawtooth output is used to look up an OSC3 sample. +// The sample is output if the pulse output is on. +// +// Pulse+Sawtooth+Triangle: +// The sawtooth output is used to look up an OSC3 sample. +// The sample is output if the pulse output is on. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output__ST() +{ + return wave__ST[output__S_()] << 4; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::output_P_T() +{ + /* ring modulation does something odd with this waveform. But I don't know + * how to emulate it. */ + return (wave_P_T[output___T() >> 1] << 4) & output_P__(); +} + +RESID_INLINE +reg12 WaveformGeneratorFP::output_PS_() +{ + return (wave_PS_[output__S_()] << 4) & output_P__(); +} + +RESID_INLINE +reg12 WaveformGeneratorFP::output_PST() +{ + return (wave_PST[output__S_()] << 4) & output_P__(); +} + +// Combined waveforms including noise: +// All waveform combinations including noise output zero after a few cycles. +// NB! The effects of such combinations are not fully explored. It is claimed +// that the shift register may be filled with zeroes and locked up, which +// seems to be true. +// We have not attempted to model this behavior, suffice to say that +// there is very little audible output from waveform combinations including +// noise. We hope that nobody is actually using it. +// +RESID_INLINE +reg12 WaveformGeneratorFP::outputN__T() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputN_S_() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputN_ST() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNP__() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNP_T() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNPS_() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNPST() +{ + return 0; +} + +// ---------------------------------------------------------------------------- +// Select one of 16 possible combinations of waveforms. +// ---------------------------------------------------------------------------- +RESID_INLINE +reg12 WaveformGeneratorFP::output() +{ + switch (waveform) { + case 0x1: + previous = output___T(); + break; + case 0x2: + previous = output__S_(); + break; + case 0x3: + previous = output__ST(); + break; + case 0x4: + previous = output_P__(); + break; + case 0x5: + previous = output_P_T(); + break; + case 0x6: + previous = output_PS_(); + break; + case 0x7: + previous = output_PST(); + break; + case 0x8: + previous = noise_output_cached; + break; + case 0x9: + previous = outputN__T(); + break; + case 0xa: + previous = outputN_S_(); + break; + case 0xb: + previous = outputN_ST(); + break; + case 0xc: + previous = outputNP__(); + break; + case 0xd: + previous = outputNP_T(); + break; + case 0xe: + previous = outputNPS_(); + break; + case 0xf: + previous = outputNPST(); + break; + default: + break; + } + return previous; +} + +#endif // not __WAVE_H__ diff --git a/src/resid-fp/wave6581_PST.cc b/src/resid-fp/wave6581_PST.cc new file mode 100644 index 000000000..19d2126ef --- /dev/null +++ b/src/resid-fp/wave6581_PST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave6581_PST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, +/* 0x7f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +/* 0x7f8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, +/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +/* 0xff8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f, +}; diff --git a/src/resid-fp/wave6581_PST.dat b/src/resid-fp/wave6581_PST.dat new file mode 100644 index 0000000000000000000000000000000000000000..5afe75e22e10a8f0ea80f90eade17858e9123946 GIT binary patch literal 4096 zcmZP=1*0J_8UiCV1nftu$4C7=8UiCQ1QeitHeg_2sHmu`uZQwSsnHM^4S|st0;Bc+ P$cyt)ACKG+z^MNL_wxn! literal 0 HcmV?d00001 diff --git a/src/resid-fp/wave6581_PS_.cc b/src/resid-fp/wave6581_PS_.cc new file mode 100644 index 000000000..bf133e542 --- /dev/null +++ b/src/resid-fp/wave6581_PS_.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave6581_PS_[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f, +/* 0x3f8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f, +/* 0x5f8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x6d, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f, +/* 0x6f8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x738: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x758: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x768: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76, +/* 0x770: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77, +/* 0x778: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x798: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b, +/* 0x7b8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d, +/* 0x7d8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d, +/* 0x7e0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e, +/* 0x7e8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, +/* 0x7f0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, +/* 0x7f8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f, +/* 0xbf8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f, +/* 0xdf8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6d, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f, +/* 0xef8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77, +/* 0xf78: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b, +/* 0xfb8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d, +/* 0xfd8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d, +/* 0xfe0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e, +/* 0xfe8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, +/* 0xff0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7c, 0x7f, 0x7f, 0x7f, +/* 0xff8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +}; diff --git a/src/resid-fp/wave6581_PS_.dat b/src/resid-fp/wave6581_PS_.dat new file mode 100644 index 0000000000000000000000000000000000000000..ea2fb9c5397c69f7cfcb23df61182876a599071f GIT binary patch literal 4096 zcmZP=*?@h3z0XXc{S@kFlBdvqO0`qyeg;Mg9iUI4eoD2QQ)qxS0sXdU@^%oufjxtP zg}t4lp2c^Cy!2V#S0kormx2doFAzo4Lsfq|ib zp`f7Jp`f6;qPn^oDqjE +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave6581_P_T[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x38, 0x3f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x5f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x378: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x6f, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x70, 0x77, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7b, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x70, +/* 0x3e8: */ 0x00, 0x40, 0x40, 0x70, 0x60, 0x70, 0x78, 0x7d, +/* 0x3f0: */ 0x00, 0x40, 0x60, 0x78, 0x60, 0x78, 0x78, 0x7e, +/* 0x3f8: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x9f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x578: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0xa0, 0xa0, 0xaf, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, +/* 0x5b8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xa0, 0xb0, 0xb7, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, +/* 0x5d8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xb0, 0xb0, 0xbb, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xb0, +/* 0x5e8: */ 0x80, 0x80, 0x80, 0xb0, 0x80, 0xb0, 0xb8, 0xbd, +/* 0x5f0: */ 0x80, 0x80, 0x80, 0xb8, 0xa0, 0xb8, 0xb8, 0xbe, +/* 0x5f8: */ 0xa0, 0xb8, 0xbc, 0xbf, 0xbe, 0xbf, 0xbf, 0xbf, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x670: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x678: */ 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x698: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0xc0, 0xc0, +/* 0x6b8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd7, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0x6d0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, +/* 0x6d8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd0, 0xdb, +/* 0x6e0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xd0, +/* 0x6e8: */ 0x80, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd8, 0xdd, +/* 0x6f0: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd8, 0xd8, 0xde, +/* 0x6f8: */ 0xc0, 0xd8, 0xdc, 0xdf, 0xdc, 0xdf, 0xdf, 0xdf, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x718: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x728: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x730: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x738: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe7, +/* 0x740: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x748: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x750: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x758: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xeb, +/* 0x760: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0x768: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xed, +/* 0x770: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, 0xe8, 0xee, +/* 0x778: */ 0xe0, 0xe8, 0xec, 0xef, 0xec, 0xef, 0xef, 0xef, +/* 0x780: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0x788: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xf0, +/* 0x790: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0, +/* 0x798: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf3, +/* 0x7a0: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xf0, +/* 0x7a8: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf5, +/* 0x7b0: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf6, +/* 0x7b8: */ 0xf0, 0xf0, 0xf4, 0xf7, 0xf4, 0xf7, 0xf7, 0xf7, +/* 0x7c0: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, +/* 0x7c8: */ 0xe0, 0xe0, 0xe0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf9, +/* 0x7d0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xfa, +/* 0x7d8: */ 0xf0, 0xf8, 0xf8, 0xfb, 0xf8, 0xfb, 0xfb, 0xfb, +/* 0x7e0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xfc, 0xfc, +/* 0x7e8: */ 0xf8, 0xfc, 0xfc, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, +/* 0x7f0: */ 0xf8, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0x7f8: */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0x800: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, +/* 0x808: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, +/* 0x810: */ 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfc, 0xfc, 0xf8, +/* 0x818: */ 0xfc, 0xfc, 0xfc, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0, +/* 0x820: */ 0xfb, 0xfb, 0xfb, 0xf8, 0xfb, 0xf8, 0xf8, 0xf0, +/* 0x828: */ 0xfa, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0, +/* 0x830: */ 0xf9, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xe0, 0xe0, +/* 0x838: */ 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, +/* 0x840: */ 0xf7, 0xf7, 0xf7, 0xf4, 0xf7, 0xf4, 0xf0, 0xf0, +/* 0x848: */ 0xf6, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, +/* 0x850: */ 0xf5, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0, +/* 0x858: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80, +/* 0x860: */ 0xf3, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0, +/* 0x868: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x870: */ 0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, +/* 0x878: */ 0xc0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0x880: */ 0xef, 0xef, 0xef, 0xec, 0xef, 0xec, 0xe8, 0xe0, +/* 0x888: */ 0xee, 0xe8, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, +/* 0x890: */ 0xed, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, +/* 0x898: */ 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, +/* 0x8a0: */ 0xeb, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, +/* 0x8a8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8b0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8b8: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0xe7, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80, +/* 0x8c8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8d0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8d8: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0xe0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x900: */ 0xdf, 0xdf, 0xdf, 0xdc, 0xdf, 0xdc, 0xd8, 0xc0, +/* 0x908: */ 0xde, 0xd8, 0xd8, 0xc0, 0xd8, 0xc0, 0xc0, 0xc0, +/* 0x910: */ 0xdd, 0xd8, 0xd0, 0xc0, 0xd0, 0xc0, 0xc0, 0x80, +/* 0x918: */ 0xd0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x920: */ 0xdb, 0xd0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x928: */ 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x930: */ 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0x938: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0xd7, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x948: */ 0xc0, 0xc0, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x950: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x958: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x968: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x980: */ 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x00, +/* 0x988: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x990: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa00: */ 0xbf, 0xbf, 0xbf, 0xbe, 0xbf, 0xbc, 0xbc, 0xa0, +/* 0xa08: */ 0xbe, 0xbc, 0xb8, 0xa0, 0xb8, 0xa0, 0x80, 0x80, +/* 0xa10: */ 0xbd, 0xb8, 0xb0, 0x80, 0xb0, 0x80, 0x80, 0x80, +/* 0xa18: */ 0xb0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xa20: */ 0xbb, 0xb0, 0xb0, 0x80, 0xa0, 0x80, 0x80, 0x00, +/* 0xa28: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xa30: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0xb7, 0xb0, 0xa0, 0x80, 0xa0, 0x80, 0x80, 0x00, +/* 0xa48: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa80: */ 0xaf, 0xa0, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x00, +/* 0xa88: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x9f, 0x90, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc00: */ 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7c, 0x7c, 0x70, +/* 0xc08: */ 0x7e, 0x7c, 0x78, 0x60, 0x78, 0x60, 0x60, 0x00, +/* 0xc10: */ 0x7d, 0x78, 0x78, 0x60, 0x70, 0x40, 0x40, 0x00, +/* 0xc18: */ 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x7b, 0x78, 0x70, 0x40, 0x70, 0x40, 0x00, 0x00, +/* 0xc28: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x77, 0x70, 0x70, 0x00, 0x60, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x6f, 0x60, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x5f, 0x58, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe00: */ 0x3f, 0x3c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src/resid-fp/wave6581_P_T.dat b/src/resid-fp/wave6581_P_T.dat new file mode 100644 index 0000000000000000000000000000000000000000..1cc8874da796bf210ffddb17d0382a86763bcc81 GIT binary patch literal 4096 zcmZP=1tT{E6fEpVuICvX7#tkp>Fj?8sC^(hfgvFwAIir?fz%<(B|teKI)Ndfpd8AF zQ6O;;8$=g46ckj0I1CI91q==j1qlTewG0jk6$up;bpy|2^$__1BO55RnUH>T zc^Dr=H#9Uf%pWlOLAEbgu%3YZAa^2^G&F$t4Gawp3qZJG!G`TnNrX59144eohTRMd z3?Q2}G&D49XxOl0Z$m@Fjs-h*>|3y7&;EV;_wR@5Czm>aS7Sp1vOLILAU=d{XgF}- zz=88<`a%8x34v&cIuH-!ClH31*TB$l-~d?nfeY6m(hOkrAR`$X8o+X3`3o0rL-`jP z4ji~};KGf&2SD_V8}|;}xO4x`{rmT!`e78v91t5sgN%Cs;()>sYR&@~-EiQ*g98s9 zJcr4_#9{P-0|y>Fc<|sg$Pf@4%zN%)&9zkmGx{Tssn^XJE(KY#!H{rmUFpMMbW9|b_f{{8v!_wV07f5FQCeE9LnJ2QC~q&;Y_9^KM_b0Cot-?I8Yv1F%d8(#^nd9V`t>at+`_2vP&G1B5{; z(D^WNkQ@k~2biD5C-vKG>8qtP-8$$ stT;a*0jwXU4n|{DOasCA2nPm`oghpD;|INw_BIBC-i@OUq+JLA09r(7w*UYD literal 0 HcmV?d00001 diff --git a/src/resid-fp/wave6581__ST.cc b/src/resid-fp/wave6581__ST.cc new file mode 100644 index 000000000..d193550f2 --- /dev/null +++ b/src/resid-fp/wave6581__ST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave6581__ST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0x3f8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7e8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7f0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, +/* 0x7f8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0xbf8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0xfe8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0xff0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, +/* 0xff8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, +}; diff --git a/src/resid-fp/wave6581__ST.dat b/src/resid-fp/wave6581__ST.dat new file mode 100644 index 0000000000000000000000000000000000000000..2e5d9872c4c49b4edaa126cdad13263d54bd916b GIT binary patch literal 4096 zcmZP=P{7Pgq4kWE=x1kVXQxCz0|Ns^_A@XHod5aw`1ttw`S~gIKZV){&i^2XkHq+w zfdV->IXQWGdwWng3>+Sfe+t8%?D7Yi|K%yPpF-`U@lRm@5{!QfG++Y-c6Rpm_4W1j z6xvUr_R;vKFaQb0KQ8m3`G2(j#}z=tiIW}v5aa2e{-M>s%xL}3z%UZqe~@&?zyQtv ZqxC;5K**y9ef~$Q{w<)@zYVPZ2LK$87##or literal 0 HcmV?d00001 diff --git a/src/resid-fp/wave8580_PST.cc b/src/resid-fp/wave8580_PST.cc new file mode 100644 index 000000000..51ae21612 --- /dev/null +++ b/src/resid-fp/wave8580_PST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave8580_PST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, +/* 0x7f0: */ 0x60, 0x20, 0x70, 0x70, 0x70, 0x70, 0x70, 0x78, +/* 0x7f8: */ 0x78, 0x78, 0x7c, 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1e, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xdf8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8c, 0x9f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe80: */ 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0xe88: */ 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0xef0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xef8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, +/* 0xf00: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf08: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf10: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf18: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf20: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf28: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf30: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf38: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf40: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf48: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf50: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf58: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf68: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xf70: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, +/* 0xf80: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf88: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf90: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf98: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xfa0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xfa8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xfb0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, +/* 0xfb8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfc0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfc8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfd0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfd8: */ 0xf0, 0xf0, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfe0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfe8: */ 0xf8, 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xff0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, +/* 0xff8: */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/src/resid-fp/wave8580_PST.dat b/src/resid-fp/wave8580_PST.dat new file mode 100644 index 0000000000000000000000000000000000000000..22706cf250b5c0e602bdd8db33b83aed623b1c82 GIT binary patch literal 4096 zcmZP=1*0J_8UiCV1ms7m$4C7=8UiCP1QZGq6be9~qN1Xvrmn8Oe&mJ0sEh literal 0 HcmV?d00001 diff --git a/src/resid-fp/wave8580_PS_.cc b/src/resid-fp/wave8580_PS_.cc new file mode 100644 index 000000000..e33a2cee5 --- /dev/null +++ b/src/resid-fp/wave8580_PS_.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave8580_PS_[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x1f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +/* 0x3f8: */ 0x00, 0x0c, 0x1c, 0x3f, 0x1e, 0x3f, 0x3f, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, +/* 0x5f8: */ 0x00, 0x00, 0x00, 0x5f, 0x0c, 0x5f, 0x5f, 0x5f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, +/* 0x6f8: */ 0x00, 0x40, 0x40, 0x6f, 0x40, 0x6f, 0x6f, 0x6f, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x61, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x768: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x70, +/* 0x770: */ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, +/* 0x778: */ 0x40, 0x60, 0x60, 0x77, 0x60, 0x77, 0x77, 0x77, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, +/* 0x798: */ 0x00, 0x40, 0x40, 0x60, 0x40, 0x60, 0x60, 0x79, +/* 0x7a0: */ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x60, +/* 0x7a8: */ 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x78, +/* 0x7b0: */ 0x40, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, +/* 0x7b8: */ 0x60, 0x70, 0x70, 0x78, 0x70, 0x79, 0x7b, 0x7b, +/* 0x7c0: */ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x70, +/* 0x7c8: */ 0x60, 0x60, 0x60, 0x70, 0x60, 0x70, 0x70, 0x7c, +/* 0x7d0: */ 0x60, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x7c, +/* 0x7d8: */ 0x70, 0x78, 0x78, 0x7c, 0x78, 0x7c, 0x7c, 0x7d, +/* 0x7e0: */ 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x7c, +/* 0x7e8: */ 0x78, 0x7c, 0x7c, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, +/* 0x7f0: */ 0x7c, 0x7c, 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +/* 0x7f8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x8d, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x8e, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x8f, +/* 0x9f8: */ 0x80, 0x80, 0x80, 0x9f, 0x80, 0x9f, 0x9f, 0x9f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x87, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x83, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0xad8: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +/* 0xae0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xae8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x84, +/* 0xaf0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x87, +/* 0xaf8: */ 0x80, 0x80, 0x80, 0x87, 0x80, 0x8f, 0xaf, 0xaf, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, +/* 0xb28: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x83, +/* 0xb40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +/* 0xb60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0xb70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0xb78: */ 0x80, 0x80, 0x80, 0xa0, 0x80, 0xa3, 0xb7, 0xb7, +/* 0xb80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb1, +/* 0xba0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xba8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb0, +/* 0xbb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb0, +/* 0xbb8: */ 0x80, 0xa0, 0xa0, 0xb0, 0xa0, 0xb8, 0xb9, 0xbb, +/* 0xbc0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0xbc8: */ 0x80, 0x80, 0x80, 0xa0, 0x80, 0xa0, 0xa0, 0xb8, +/* 0xbd0: */ 0x80, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xb8, +/* 0xbd8: */ 0xa0, 0xb0, 0xb0, 0xb8, 0xb0, 0xbc, 0xbc, 0xbd, +/* 0xbe0: */ 0xa0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb8, 0xb8, 0xbc, +/* 0xbe8: */ 0xb0, 0xb8, 0xb8, 0xbc, 0xb8, 0xbc, 0xbe, 0xbe, +/* 0xbf0: */ 0xb8, 0xbc, 0xbc, 0xbe, 0xbc, 0xbe, 0xbe, 0xbf, +/* 0xbf8: */ 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, +/* 0xc10: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc18: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc28: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +/* 0xc40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc7, +/* 0xc80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xca0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xca8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xcb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xcb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc3, +/* 0xcc0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xcc8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xcd0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xcd8: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc1, +/* 0xce0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xce8: */ 0x80, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xcf0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc7, +/* 0xcf8: */ 0xc0, 0xc0, 0xc0, 0xc7, 0xc0, 0xcf, 0xcf, 0xcf, +/* 0xd00: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd08: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd10: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd18: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xd20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd28: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xd30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0xd38: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc3, +/* 0xd40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xd48: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, +/* 0xd50: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd58: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, +/* 0xd60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd68: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd70: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd78: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc7, 0xd7, +/* 0xd80: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd88: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd90: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd98: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xda0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xda8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, +/* 0xdb0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, +/* 0xdb8: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd8, 0xdb, +/* 0xdc0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xdc8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd8, +/* 0xdd0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd8, +/* 0xdd8: */ 0xc0, 0xc0, 0xc0, 0xd8, 0xd0, 0xd8, 0xd8, 0xdd, +/* 0xde0: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd0, 0xdc, +/* 0xde8: */ 0xd0, 0xd8, 0xd8, 0xdc, 0xd8, 0xdc, 0xdc, 0xde, +/* 0xdf0: */ 0xd8, 0xdc, 0xdc, 0xde, 0xdc, 0xde, 0xde, 0xdf, +/* 0xdf8: */ 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, +/* 0xe00: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe08: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe10: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe18: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe20: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe28: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe30: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe38: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe3, +/* 0xe40: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe48: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe50: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xe58: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe1, +/* 0xe60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xe68: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xe70: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xe78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe3, 0xe7, +/* 0xe80: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xe88: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xe90: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xe98: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xea0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xea8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xeb0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xeb8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xeb, +/* 0xec0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xec8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xed0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xed8: */ 0xe0, 0xe0, 0xe0, 0xe8, 0xe0, 0xe8, 0xe8, 0xed, +/* 0xee0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xec, +/* 0xee8: */ 0xe0, 0xe0, 0xe0, 0xec, 0xe8, 0xec, 0xec, 0xee, +/* 0xef0: */ 0xe8, 0xe8, 0xe8, 0xec, 0xec, 0xee, 0xee, 0xef, +/* 0xef8: */ 0xec, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, +/* 0xf00: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf08: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf10: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf18: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, +/* 0xf20: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, +/* 0xf28: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf0, +/* 0xf30: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf38: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, +/* 0xf40: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf48: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf50: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf58: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf5, +/* 0xf60: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf68: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, 0xf4, 0xf6, +/* 0xf70: */ 0xf0, 0xf0, 0xf0, 0xf4, 0xf0, 0xf4, 0xf6, 0xf7, +/* 0xf78: */ 0xf4, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, +/* 0xf80: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, +/* 0xf88: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, 0xf8, 0xf8, +/* 0xf90: */ 0xf0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf8, +/* 0xf98: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, +/* 0xfa0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfa8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfa, +/* 0xfb0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, +/* 0xfb8: */ 0xf8, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, +/* 0xfc0: */ 0xf8, 0xf8, 0xf8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, +/* 0xfc8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xfd0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, +/* 0xfd8: */ 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, +/* 0xfe0: */ 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0xfe8: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0xff0: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0xff8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/src/resid-fp/wave8580_PS_.dat b/src/resid-fp/wave8580_PS_.dat new file mode 100644 index 0000000000000000000000000000000000000000..9a20a9eee6211222f5b21d98b9223e5aa1b3891c GIT binary patch literal 4096 zcmZP=Sinr7^^6qi=ciCVrP|pkG=Na};SV2nc6kczr&K#3_Y*RokbeCBXJDi>{t1{* z$oUN71XbWyV2xjz!4^&44$8M@;E}PHv$wa0@&}3{6n})=MQQjCbo^7A|G5bS5Eq(! z9F!l=z`zjC6CV$vp+aO)l!m`MS+*iHIU|@@S*d8Ec~E{ngM&l9LwbUYAR}KY6~jB0K~4VsjI82si~=} ztFNyI;rjae|1gUOh#u(t-%p{xDNX14jeds;QaaXP;U%`$6Jhu?CPR0v|*$v9Jyvzm7!| zpU?%UB#6Fn;KGgDP(F;h0cC*b8y9ZexO?EhfeQyNT)1=L#*I5S?%cTt!guc7yMOOK z1VGi3OFhP+@xg%u2Ob=F@Zcd-9?XC6-~mVsL_zSw$Ip@F4}jz$`XKUz$=7(4ym;{9 z#apQSn+Fdbym|5F&AS&bK;*mkZ{9-yR2~=g0V)BaKRo#G0Ze~DfX@#efJ6}jXsoX& z{4Za=efaR<%ZD%DzJK}l?K=oS<$r+bA3s3!j}JfK;3u2~Vf=znKYsuC_3JkX{P^+X Y&yPPC;P0P5fBu5NpFjUlz<)FV00fcV761SM literal 0 HcmV?d00001 diff --git a/src/resid-fp/wave8580_P_T.cc b/src/resid-fp/wave8580_P_T.cc new file mode 100644 index 000000000..206a91728 --- /dev/null +++ b/src/resid-fp/wave8580_P_T.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave8580_P_T[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x3c, 0x3f, 0x3f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5e, 0x5f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x378: */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x60, 0x60, 0x6f, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x60, +/* 0x3b8: */ 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x70, 0x77, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, +/* 0x3c8: */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, +/* 0x3d0: */ 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x70, +/* 0x3d8: */ 0x60, 0x60, 0x60, 0x70, 0x70, 0x70, 0x78, 0x7b, +/* 0x3e0: */ 0x60, 0x60, 0x60, 0x70, 0x60, 0x70, 0x70, 0x70, +/* 0x3e8: */ 0x70, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x7c, +/* 0x3f0: */ 0x78, 0x78, 0x78, 0x7c, 0x78, 0x7c, 0x7c, 0x7e, +/* 0x3f8: */ 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4d8: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4e8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4f0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4f8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8e, 0x9f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, +/* 0x530: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x538: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x540: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, +/* 0x548: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x550: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x558: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x560: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x568: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x570: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x578: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xaf, +/* 0x580: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x588: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x590: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x598: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5a0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5a8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5b0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5b8: */ 0x80, 0x80, 0x80, 0xa0, 0xa0, 0xa0, 0xa0, 0xb7, +/* 0x5c0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5c8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0x5d0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, 0xa0, +/* 0x5d8: */ 0xa0, 0xa0, 0xa0, 0xb0, 0xa0, 0xb0, 0xb0, 0xbb, +/* 0x5e0: */ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xb0, 0xb0, +/* 0x5e8: */ 0xa0, 0xb0, 0xb0, 0xb8, 0xb0, 0xb8, 0xb8, 0xbc, +/* 0x5f0: */ 0xb0, 0xb8, 0xb8, 0xb8, 0xb8, 0xbc, 0xbc, 0xbe, +/* 0x5f8: */ 0xbc, 0xbc, 0xbe, 0xbf, 0xbe, 0xbf, 0xbf, 0xbf, +/* 0x600: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x608: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x610: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x618: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x620: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x628: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x630: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x638: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0x640: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x648: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x650: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0x658: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x660: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, +/* 0x668: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x670: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x678: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, +/* 0x680: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0x688: */ 0xc0, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x690: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x698: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6a0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6a8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6b0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6b8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd7, +/* 0x6c0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6c8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6d0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6d8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd0, 0xd9, +/* 0x6e0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, +/* 0x6e8: */ 0xc0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd8, 0xd8, 0xdc, +/* 0x6f0: */ 0xd0, 0xd0, 0xd8, 0xd8, 0xd8, 0xdc, 0xdc, 0xde, +/* 0x6f8: */ 0xdc, 0xdc, 0xde, 0xdf, 0xde, 0xdf, 0xdf, 0xdf, +/* 0x700: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x708: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x710: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x718: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0x720: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0x728: */ 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x730: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x738: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe7, +/* 0x740: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x748: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x750: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x758: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, +/* 0x760: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x768: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, 0xec, +/* 0x770: */ 0xe0, 0xe0, 0xe0, 0xe8, 0xe8, 0xe8, 0xec, 0xee, +/* 0x778: */ 0xec, 0xec, 0xec, 0xee, 0xee, 0xef, 0xef, 0xef, +/* 0x780: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x788: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, +/* 0x790: */ 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x798: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x7a0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x7a8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, +/* 0x7b0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, +/* 0x7b8: */ 0xf0, 0xf4, 0xf4, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, +/* 0x7c0: */ 0xf0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf8, +/* 0x7c8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x7d0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x7d8: */ 0xf8, 0xf8, 0xf8, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, +/* 0x7e0: */ 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0x7e8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, +/* 0x7f0: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0x7f8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0x800: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0x808: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, +/* 0x810: */ 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0x818: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, +/* 0x820: */ 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xf8, 0xf8, 0xf8, +/* 0x828: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x830: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x838: */ 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x840: */ 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf4, 0xf4, 0xf0, +/* 0x848: */ 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x850: */ 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x858: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x860: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x868: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, +/* 0x870: */ 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x878: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x880: */ 0xef, 0xef, 0xef, 0xee, 0xee, 0xec, 0xec, 0xe8, +/* 0x888: */ 0xee, 0xec, 0xe8, 0xe8, 0xe8, 0xe0, 0xe0, 0xe0, +/* 0x890: */ 0xec, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x898: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8a0: */ 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8a8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8b0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8b8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8c0: */ 0xe7, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8c8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8d0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, +/* 0x8d8: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8e0: */ 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8e8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8f0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8f8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x900: */ 0xdf, 0xdf, 0xdf, 0xde, 0xdf, 0xde, 0xdc, 0xdc, +/* 0x908: */ 0xde, 0xdc, 0xdc, 0xd8, 0xd8, 0xd8, 0xd0, 0xd0, +/* 0x910: */ 0xdc, 0xd8, 0xd8, 0xd0, 0xd0, 0xd0, 0xd0, 0xc0, +/* 0x918: */ 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x920: */ 0xd9, 0xd0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x928: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x930: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x938: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x940: */ 0xd7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x948: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x950: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x958: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x960: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x968: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x970: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x978: */ 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x980: */ 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x988: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x990: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x998: */ 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x80, +/* 0x9a0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, +/* 0x9a8: */ 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9b0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9b8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9c0: */ 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9c8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9d0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9d8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9e0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9e8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9f0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9f8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa00: */ 0xbf, 0xbf, 0xbf, 0xbe, 0xbf, 0xbe, 0xbc, 0xbc, +/* 0xa08: */ 0xbe, 0xbc, 0xbc, 0xb8, 0xb8, 0xb8, 0xb8, 0xb0, +/* 0xa10: */ 0xbc, 0xb8, 0xb8, 0xb0, 0xb8, 0xb0, 0xb0, 0xb0, +/* 0xa18: */ 0xb0, 0xb0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, +/* 0xa20: */ 0xbb, 0xb0, 0xb0, 0xa0, 0xb0, 0xa0, 0xa0, 0xa0, +/* 0xa28: */ 0xa0, 0xa0, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa30: */ 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa40: */ 0xb7, 0xb0, 0xa0, 0xa0, 0xa0, 0x80, 0x80, 0x80, +/* 0xa48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa80: */ 0xaf, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xaa0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xaa8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xab0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xab8: */ 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xac8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, +/* 0xad0: */ 0x80, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x9f, 0x9e, 0x88, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb08: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb10: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb18: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc00: */ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7c, +/* 0xc08: */ 0x7e, 0x7c, 0x7c, 0x78, 0x7c, 0x78, 0x78, 0x78, +/* 0xc10: */ 0x7c, 0x78, 0x78, 0x78, 0x78, 0x70, 0x70, 0x70, +/* 0xc18: */ 0x78, 0x70, 0x70, 0x60, 0x70, 0x60, 0x60, 0x60, +/* 0xc20: */ 0x7b, 0x78, 0x70, 0x70, 0x70, 0x60, 0x60, 0x60, +/* 0xc28: */ 0x70, 0x60, 0x60, 0x60, 0x60, 0x40, 0x40, 0x40, +/* 0xc30: */ 0x60, 0x60, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, +/* 0xc38: */ 0x40, 0x40, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x77, 0x70, 0x60, 0x60, 0x60, 0x60, 0x40, 0x40, +/* 0xc48: */ 0x60, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x6f, 0x64, 0x60, 0x40, 0x40, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x5f, 0x5e, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe00: */ 0x3f, 0x3f, 0x3e, 0x00, 0x1c, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf00: */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src/resid-fp/wave8580_P_T.dat b/src/resid-fp/wave8580_P_T.dat new file mode 100644 index 0000000000000000000000000000000000000000..5423dd9ac0a80527813e1c85b3b5b60fd0ffe753 GIT binary patch literal 4096 zcmZP=*?@fndtZjZ#@>De`=5be90Q1m^zWD^~hnWXb)&MdR-8hi>AaQh)iR7;*QXMvB3l=O`upLce z0fY~dTCickh7G&HtOXlD>>V3+?AWtm$BrF4_UzfWXV1R<`}XhO4^dApdEfvJod+5k z4uC;JL&E_m6U;{=&O`JcIDk(PnjU2Cbz}|(`@)5rP_YXKE?l^9;l_c2Od0l0F`)f0K|EK0iI)spbES|~mO{{069|Iq+c z_|MckkZ3dGYSe zix;54dIKVmRG@K@WFSoJ5pduDJmTO{2#rZJ>i+%v_wIvI!<{=fZrr$V;SPwnaN)oO zsJfdMU@WKr8ihXrqA5mjL0JNv^v@&2&{++j%monyWg@V03<8vMFa${u*uQ`OzWt!m zV9y><$*^J1jvX6zYybgB$*~($bU>J3Q=tV6m<=MfZ&p(REnFlJ|L3|Jm)dR8<$^=uODhOQ+EI}keiC!YDz^e?@ z2B@#AtEsE0fi?~*Dk=&J3MvW;z>SD%5C`0dfHy8cEe#N605wL+K`jkXYXmF;YSe&4 v5mut|5aKXaeo6wQQ3Dg8GaVo2LuVTYmv#2`b__Cu%Sm)~%}DM5f&v- +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave8580__ST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0x3f8: */ 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7e8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7f0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3e, +/* 0x7f8: */ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0xbf8: */ 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x1f, 0x1f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x83, 0x83, +/* 0xe80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xef0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xef8: */ 0x80, 0x80, 0x80, 0x80, 0x87, 0x87, 0x87, 0x8f, +/* 0xf00: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xf08: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf10: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf18: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf20: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xf28: */ 0xe0, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, +/* 0xf30: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf38: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf40: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf48: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf50: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf58: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf60: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf68: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf70: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, +/* 0xf80: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf88: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf90: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf98: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfa0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfa8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfb0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfb8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, +/* 0xfc0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfc8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfd0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfd8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfe0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xfe8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xff0: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0xff8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/src/resid-fp/wave8580__ST.dat b/src/resid-fp/wave8580__ST.dat new file mode 100644 index 0000000000000000000000000000000000000000..f30002ceb01ae93d2da7b9e91431a0616a25861a GIT binary patch literal 4096 zcmZP=P{7PQkk+%av$GGR{R|8P=YKvvK0bbae*Tf_e~`b2LHsj<{6PwqfdV->c`zVF zFZI<9T>1z3Wf;Ui$Qxu~X#STcOEc9pjmAHPK}j(GTc80O2(YV%0t)S?Q2S{7Qy73` zYlr6l(fXh45Tu4iiqk*A{EzNRX!S1xssHWm(dFsOr`Z1#Id>S;|0KshEWjZ7Uw%OA z{|1KU=7s?T?d|RT2Oc~)aNxlM5P1L$psWXA&H<1d2!mBT04oGBsf8au{y-V{_=5oW Mg9iRV!G9 literal 0 HcmV?d00001 diff --git a/src/resources.h b/src/resources.h new file mode 100644 index 000000000..b5c9bccc6 --- /dev/null +++ b/src/resources.h @@ -0,0 +1,139 @@ +#define IDM_FILE_RESET 40000 +#define IDM_FILE_HRESET 40001 +#define IDM_FILE_EXIT 40002 +#define IDM_FILE_RESET_CAD 40003 +#define IDM_DISC_A 40010 +#define IDM_DISC_B 40011 +#define IDM_EJECT_A 40012 +#define IDM_EJECT_B 40013 +#define IDM_HDCONF 40014 +#define IDM_CONFIG 40020 +#define IDM_CONFIG_LOAD 40021 +#define IDM_CONFIG_SAVE 40022 +#define IDM_STATUS 40030 +#define IDM_VID_RESIZE 40050 +#define IDM_VID_REMEMBER 40051 +#define IDM_VID_DDRAW 40060 +#define IDM_VID_D3D 40061 +#define IDM_VID_FULLSCREEN 40070 +#define IDM_VID_FS_FULL 40071 +#define IDM_VID_FS_43 40072 +#define IDM_VID_FS_SQ 40073 +#define IDM_VID_FS_INT 40074 +#define IDM_CDROM_ISO 40100 +#define IDM_CDROM_EMPTY 40200 +#define IDM_CDROM_REAL 40200 +#define IDM_CDROM_DISABLED 40300 + +#define IDC_COMBO1 1000 +#define IDC_COMBOVID 1001 +#define IDC_COMBO3 1002 +#define IDC_COMBO4 1003 +#define IDC_COMBO5 1004 +#define IDC_COMBO386 1005 +#define IDC_COMBO486 1006 +#define IDC_COMBOSND 1007 +#define IDC_COMBOCHC 1008 +#define IDC_COMBONET 1009 +#define IDC_COMBOCPUM 1060 +#define IDC_COMBOSPD 1061 +#define IDC_COMBODRA 1062 +#define IDC_COMBODRB 1063 +#define IDC_COMBOJOY 1064 +#define IDC_CHECK1 1010 +#define IDC_CHECK2 1011 +#define IDC_CHECK3 1012 +#define IDC_CHECK4 1013 +#define IDC_CHECKGUS 1014 +#define IDC_CHECKSSI 1015 +#define IDC_CHECKVOODOO 1016 +#define IDC_CHECKDYNAREC 1017 +#define IDC_STATIC 1020 +#define IDC_CHECKFORCE43 1021 +#define IDC_CHECKOVERSCAN 1022 +#define IDC_CHECKCBURST 1023 +#define IDC_CHECKBROWN 1024 +#define IDC_CHECKFLASH 1025 +#define IDC_CHECKSYNC 1026 +#define IDC_CHECKSERIAL 1027 +#define IDC_EDIT1 1030 +#define IDC_EDIT2 1031 +#define IDC_EDIT3 1032 +#define IDC_EDIT4 1033 +#define IDC_EDIT5 1034 +#define IDC_EDIT6 1035 +#define IDC_TEXT1 1040 +#define IDC_TEXT2 1041 +#define IDC_EDITC 1050 +#define IDC_CFILE 1051 +#define IDC_CNEW 1052 +#define IDC_EDITD 1053 +#define IDC_DFILE 1054 +#define IDC_DNEW 1055 +#define IDC_EJECTC 1056 +#define IDC_EJECTD 1057 +#define IDC_EDITE 1058 +#define IDC_EFILE 1059 +#define IDC_ENEW 1060 +#define IDC_EDITF 1061 +#define IDC_FFILE 1062 +#define IDC_FNEW 1063 +#define IDC_EJECTE 1064 +#define IDC_EJECTF 1065 +#define IDC_MEMSPIN 1070 +#define IDC_MEMTEXT 1071 +#define IDC_CHDD 1080 +#define IDC_CCDROM 1081 +#define IDC_DHDD 1082 +#define IDC_DCDROM 1083 +#define IDC_EHDD 1084 +#define IDC_ECDROM 1085 +#define IDC_FHDD 1086 +#define IDC_FCDROM 1087 +#define IDC_GCDROM 1088 +#define IDC_HCDROM 1089 +#define IDC_STEXT1 1100 +#define IDC_STEXT2 1101 +#define IDC_STEXT3 1102 +#define IDC_STEXT4 1103 +#define IDC_STEXT5 1104 +#define IDC_STEXT6 1105 +#define IDC_STEXT7 1106 +#define IDC_STEXT8 1107 +#define IDC_STEXT_DEVICE 1108 +#define IDC_TEXT_MB 1120 + +#define IDC_EDIT_C_SPT 1200 +#define IDC_EDIT_C_HPC 1201 +#define IDC_EDIT_C_CYL 1202 +#define IDC_EDIT_D_SPT 1203 +#define IDC_EDIT_D_HPC 1204 +#define IDC_EDIT_D_CYL 1205 +#define IDC_EDIT_E_SPT 1206 +#define IDC_EDIT_E_HPC 1207 +#define IDC_EDIT_E_CYL 1208 +#define IDC_EDIT_F_SPT 1209 +#define IDC_EDIT_F_HPC 1210 +#define IDC_EDIT_F_CYL 1211 +#define IDC_TEXT_C_SIZE 1220 +#define IDC_TEXT_D_SIZE 1221 +#define IDC_TEXT_E_SIZE 1222 +#define IDC_TEXT_F_SIZE 1223 +#define IDC_EDIT_C_FN 1230 +#define IDC_EDIT_D_FN 1231 +#define IDC_EDIT_E_FN 1232 +#define IDC_EDIT_F_FN 1233 + +#define IDC_CONFIGUREVID 1200 +#define IDC_CONFIGURESND 1201 +#define IDC_CONFIGUREVOODOO 1202 +#define IDC_CONFIGURENET 1203 +#define IDC_JOY1 1210 +#define IDC_JOY2 1211 +#define IDC_JOY3 1212 +#define IDC_JOY4 1213 + +#define IDC_CONFIG_BASE 1200 + +#define WM_RESETD3D WM_USER +#define WM_LEAVEFULLSCREEN WM_USER + 1 diff --git a/src/rom.c b/src/rom.c new file mode 100644 index 000000000..a820a6d0a --- /dev/null +++ b/src/rom.c @@ -0,0 +1,125 @@ +#include +#include +#include "ibm.h" +#include "mem.h" +#include "rom.h" + +FILE *romfopen(char *fn, char *mode) +{ + char s[512]; + strcpy(s, pcempath); + put_backslash(s); + strcat(s, fn); + return fopen(s, mode); +} + +int rom_present(char *fn) +{ + FILE *f; + char s[512]; + + strcpy(s, pcempath); + put_backslash(s); + strcat(s, fn); + f = fopen(s, "rb"); + if (f) + { + fclose(f); + return 1; + } + return 0; +} + +static uint8_t rom_read(uint32_t addr, void *p) +{ + rom_t *rom = (rom_t *)p; +// pclog("rom_read : %08x %08x %02x\n", addr, rom->mask, rom->rom[addr & rom->mask]); + return rom->rom[addr & rom->mask]; +} +uint16_t rom_readw(uint32_t addr, void *p) +{ + rom_t *rom = (rom_t *)p; +// pclog("rom_readw: %08x %08x %04x\n", addr, rom->mask, *(uint16_t *)&rom->rom[addr & rom->mask]); + return *(uint16_t *)&rom->rom[addr & rom->mask]; +} +uint32_t rom_readl(uint32_t addr, void *p) +{ + rom_t *rom = (rom_t *)p; +// pclog("rom_readl: %08x %08x %08x\n", addr, rom->mask, *(uint32_t *)&rom->rom[addr & rom->mask]); + return *(uint32_t *)&rom->rom[addr & rom->mask]; +} + +int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags) +{ + FILE *f = romfopen(fn, "rb"); + + if (!f) + { + pclog("ROM image not found : %s\n", fn); + return -1; + } + + rom->rom = malloc(size); + fseek(f, file_offset, SEEK_SET); + fread(rom->rom, size, 1, f); + fclose(f); + + rom->mask = mask; + + mem_mapping_add(&rom->mapping, address, size, rom_read, + rom_readw, + rom_readl, + mem_write_null, + mem_write_nullw, + mem_write_nulll, + rom->rom, + flags, + rom); + + return 0; +} + +int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags) +{ + FILE *f_low = romfopen(fn_low, "rb"); + FILE *f_high = romfopen(fn_high, "rb"); + int c; + + if (!f_low || !f_high) + { + if (!f_low) + pclog("ROM image not found : %s\n", fn_low); + else + fclose(f_low); + if (!f_high) + pclog("ROM image not found : %s\n", fn_high); + else + fclose(f_high); + return -1; + } + + rom->rom = malloc(size); + fseek(f_low, file_offset, SEEK_SET); + fseek(f_high, file_offset, SEEK_SET); + for (c = 0; c < size; c += 2) + { + rom->rom[c] = getc(f_low); + rom->rom[c + 1] = getc(f_high); + } + fclose(f_high); + fclose(f_low); + + rom->mask = mask; + + mem_mapping_add(&rom->mapping, address, size, rom_read, + rom_readw, + rom_readl, + mem_write_null, + mem_write_nullw, + mem_write_nulll, + rom->rom, + flags, + rom); + + return 0; +} diff --git a/src/rom.h b/src/rom.h new file mode 100644 index 000000000..f63d63202 --- /dev/null +++ b/src/rom.h @@ -0,0 +1,12 @@ +FILE *romfopen(char *fn, char *mode); +int rom_present(char *fn); + +typedef struct rom_t +{ + uint8_t *rom; + uint32_t mask; + mem_mapping_t mapping; +} rom_t; + +int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); +int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags); diff --git a/src/scat.c b/src/scat.c new file mode 100644 index 000000000..44c4e9080 --- /dev/null +++ b/src/scat.c @@ -0,0 +1,495 @@ +/*This is the chipset used in the Award 286 clone model*/ +#include "ibm.h" +#include "io.h" +#include "scat.h" +#include "mem.h" + +static uint8_t scat_regs[256]; +static int scat_index; +static uint8_t scat_port_92 = 0; +static uint8_t scat_ems_reg_2xA = 0; +static mem_mapping_t scat_mapping[32]; +static mem_mapping_t scat_high_mapping[16]; +static scat_t scat_stat[32]; +static uint32_t scat_xms_bound; +static mem_mapping_t scat_shadowram_mapping; +static mem_mapping_t scat_512k_clip_mapping; + +void scat_shadow_state_update() +{ + int i, val, val2; + + // TODO - Segment A000 to BFFF shadow ram enable features and ROM enable features should be implemented later. + for (i = 8; i < 24; i++) + { + val = ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL; + if (i < 8) + { + val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; + } + else + { + if ((scat_regs[SCAT_RAM_WRITE_PROTECT] >> ((i - 8) >> 1)) & 1) + { + val |= MEM_WRITE_DISABLED; + } + else + { + val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; + } + mem_set_mem_state((i + 40) << 14, 0x4000, val); + } + } + + flushmmucache(); +} + +void scat_set_xms_bound(uint8_t val) +{ + uint32_t max_xms_size = (mem_size >= 16384) ? 0xFC0000 : mem_size << 10; + + switch (val) + { + case 1: + scat_xms_bound = 0x100000; + break; + case 2: + scat_xms_bound = 0x140000; + break; + case 3: + scat_xms_bound = 0x180000; + break; + case 4: + scat_xms_bound = 0x200000; + break; + case 5: + scat_xms_bound = 0x300000; + break; + case 6: + scat_xms_bound = 0x400000; + break; + case 7: + scat_xms_bound = 0x600000; + break; + case 8: + scat_xms_bound = 0x800000; + break; + case 9: + scat_xms_bound = 0xA00000; + break; + case 10: + scat_xms_bound = 0xC00000; + break; + case 11: + scat_xms_bound = 0xE00000; + break; + default: + scat_xms_bound = (mem_size >= 16384 ? 0xFC0000 : mem_size << 10); + break; + } + + if ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) + { + if (val != 1) + { + mem_mapping_enable(&scat_shadowram_mapping); + if (val == 0) + scat_xms_bound = 0x160000; + } + else + { + mem_mapping_disable(&scat_shadowram_mapping); + } + pclog("Set XMS bound(%02X) = %06X(%dKbytes for EMS access)\n", val, scat_xms_bound, (0x160000 - scat_xms_bound) >> 10); + if (scat_xms_bound > 0x100000) + mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (scat_xms_bound < 0x160000) + mem_set_mem_state(scat_xms_bound, 0x160000 - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + else + { + if (scat_xms_bound > max_xms_size) + scat_xms_bound = max_xms_size; + pclog("Set XMS bound(%02X) = %06X(%dKbytes for EMS access)\n", val, scat_xms_bound, ((mem_size << 10) - scat_xms_bound) >> 10); + if (scat_xms_bound > 0x100000) + mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (scat_xms_bound < (mem_size << 10)) + mem_set_mem_state(scat_xms_bound, (mem_size << 10) - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } +} + +uint32_t get_scat_addr(uint32_t addr, scat_t *p) +{ + if (p && (scat_regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) + { + addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; + } + else if (p == NULL && mem_size < 2048 && ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) > 7)) + addr &= 0x7FFFF; + if ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3 && addr >= 0x100000) + addr -= 0x60000; + + return addr; +} + +void scat_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t scat_reg_valid = 0, scat_shadow_update = 0, index; + uint32_t base_addr, virt_addr; + + switch (port) + { + case 0x22: + scat_index = val; + break; + + case 0x23: + switch (scat_index) + { + case SCAT_CLOCK_CONTROL: + case SCAT_PERIPHERAL_CONTROL: + case SCAT_EMS_CONTROL: + scat_reg_valid = 1; + break; + case SCAT_POWER_MANAGEMENT: + val &= 0x40; // TODO - Only use AUX parity disable bit for this version. Other bits should be implemented later. + scat_reg_valid = 1; + break; + case SCAT_DRAM_CONFIGURATION: + if((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) + { + if((val & 0x0F) == 3) + { + mem_mapping_enable(&scat_shadowram_mapping); + } + else + { + mem_mapping_disable(&scat_shadowram_mapping); + } + if(mem_size < 2048) + { + if ((val & 0x0F) > 7) mem_mapping_enable(&scat_512k_clip_mapping); + else mem_mapping_disable(&scat_512k_clip_mapping); + } + } + flushmmucache(); + scat_reg_valid = 1; + break; + case SCAT_EXTENDED_BOUNDARY: + scat_set_xms_bound(val & 0x0f); + mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + flushmmucache(); + scat_reg_valid = 1; + break; + case SCAT_ROM_ENABLE: + case SCAT_RAM_WRITE_PROTECT: + case SCAT_SHADOW_RAM_ENABLE_1: + case SCAT_SHADOW_RAM_ENABLE_2: + case SCAT_SHADOW_RAM_ENABLE_3: + scat_reg_valid = 1; + scat_shadow_update = 1; + break; + default: + break; + } + if (scat_reg_valid) + scat_regs[scat_index] = val; + if (scat_shadow_update) + scat_shadow_state_update(); + pclog("Write SCAT Register %02X to %02X at %04X:%04X\n", scat_index, val, CS, cpu_state.pc); + break; + + case 0x92: + if ((mem_a20_alt ^ val) & 2) + { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~scat_port_92 & val) & 1) + { + softresetx86(); + } + scat_port_92 = val; + break; + + case 0x208: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + scat_stat[index].regs_2x8 = val; + } + break; + case 0x209: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + scat_stat[index].regs_2x9 = val; + base_addr = (index + 16) << 14; + if(index >= 24) + base_addr += 0x30000; + + if (val & 0x80) + { + virt_addr = (((scat_stat[index].regs_2x9 & 3) << 8) | scat_stat[index].regs_2x8) << 14; + mem_mapping_enable(&scat_mapping[index]); + mem_mapping_set_exec(&scat_mapping[index], ram + get_scat_addr(virt_addr, &scat_stat[index])); + pclog("Map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); + } + else + { + mem_mapping_disable(&scat_mapping[index]); + pclog("Unmap page %d(address %06X)\n", scat_ems_reg_2xA & 0x1f, base_addr); + } + + if (scat_ems_reg_2xA & 0x80) + { + scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & 0x1f); + } + } + break; + case 0x20A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + scat_ems_reg_2xA = val; + } + break; + + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + scat_stat[index].regs_2x8 = val; + } + break; + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + scat_stat[index].regs_2x9 = val; + base_addr = (index + 16) << 14; + if (index >= 24) + base_addr += 0x30000; + + if (val & 0x80) + { + virt_addr = (((scat_stat[index].regs_2x9 & 3) << 8) | scat_stat[index].regs_2x8) << 14; + mem_mapping_enable(&scat_mapping[index]); + mem_mapping_set_exec(&scat_mapping[index], ram + get_scat_addr(virt_addr, &scat_stat[index])); + pclog("Map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); + } + else + { + mem_mapping_disable(&scat_mapping[index]); + pclog("Unmap page %d(address %05X)\n", scat_ems_reg_2xA & 0x1f, base_addr); + } + + if (scat_ems_reg_2xA & 0x80) + { + scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & 0x1f); + } + } + break; + case 0x21A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + scat_ems_reg_2xA = val; + } + break; + } +} + +uint8_t scat_read(uint16_t port, void *priv) +{ + uint8_t val = 0xff, index; + switch (port) + { + case 0x23: + switch (scat_index) + { + case SCAT_MISCELLANEOUS_STATUS: + val = (scat_regs[scat_index] & 0xbf) | ((scat_port_92 & 2) << 5); + break; + default: + val = scat_regs[scat_index]; + break; + } + pclog("Read SCAT Register %02X at %04X:%04X\n", scat_index, CS, cpu_state.pc); + break; + + case 0x92: + val = scat_port_92; + break; + + case 0x208: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + val = scat_stat[index].regs_2x8; + } + break; + case 0x209: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + val = scat_stat[index].regs_2x9; + } + break; + case 0x20A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + val = scat_ems_reg_2xA; + } + break; + + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + val = scat_stat[index].regs_2x8; + } + break; + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + val = scat_stat[index].regs_2x9; + } + break; + case 0x21A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + val = scat_ems_reg_2xA; + } + break; + } + return val; +} + +uint8_t mem_read_scatems(uint32_t addr, void *priv) +{ + uint8_t val = 0xff; + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = mem_read_ram(addr, priv); + + return val; +} +uint16_t mem_read_scatemsw(uint32_t addr, void *priv) +{ + uint16_t val = 0xffff; + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = mem_read_ramw(addr, priv); + + return val; +} +uint32_t mem_read_scatemsl(uint32_t addr, void *priv) +{ + uint32_t val = 0xffffffff; + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = mem_read_raml(addr, priv); + + return val; +} + +void mem_write_scatems(uint32_t addr, uint8_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + mem_write_ram(addr, val, priv); +} +void mem_write_scatemsw(uint32_t addr, uint16_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + mem_write_ramw(addr, val, priv); +} +void mem_write_scatemsl(uint32_t addr, uint32_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + mem_write_raml(addr, val, priv); +} + +void scat_init() +{ + int i; + + io_sethandler(0x0022, 0x0002, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + + for (i = 0; i < 256; i++) + { + scat_regs[i] = 0xff; + } + + scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + scat_regs[SCAT_VERSION] = 10; + scat_regs[SCAT_CLOCK_CONTROL] = 2; + scat_regs[SCAT_PERIPHERAL_CONTROL] = 0x80; + scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; + scat_regs[SCAT_POWER_MANAGEMENT] = 0; + scat_regs[SCAT_ROM_ENABLE] = 0xC0; + scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; + scat_regs[SCAT_DRAM_CONFIGURATION] = 2; + scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; + scat_regs[SCAT_EMS_CONTROL] = 0; + + for (i = 0; i < 32; i++) + { + scat_stat[i].regs_2x8 = 0xff; + scat_stat[i].regs_2x9 = 0x03; + mem_mapping_add(&scat_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, mem_read_scatems, mem_read_scatemsw, mem_read_scatemsl, mem_write_scatems, mem_write_scatemsw, mem_write_scatemsl, ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &scat_stat[i]); + mem_mapping_disable(&scat_mapping[i]); + } + + // TODO - Only normal CPU accessing address FF0000 to FFFFFF mapped to ROM. Normal CPU accessing address FC0000 to FEFFFF map to ROM should be implemented later. + for (i = 12; i < 16; i++) + { + mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (i << 14), 0, NULL); + } + + if (mem_size == 1024) + { + mem_mapping_add(&scat_shadowram_mapping, 0x100000, 0x60000, mem_read_scatems, mem_read_scatemsw, mem_read_scatemsl, mem_write_scatems, mem_write_scatemsw, mem_write_scatemsl, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); + } + + // Need to RAM 512kb clipping emulation if only 256KB or 64KB modules installed in memory bank. + // TODO - 512KB clipping should be applied all RAM refer. + mem_mapping_add(&scat_512k_clip_mapping, 0x80000, 0x20000, mem_read_scatems, mem_read_scatemsw, mem_read_scatemsl, mem_write_scatems, mem_write_scatemsw, mem_write_scatemsl, ram, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_disable(&scat_512k_clip_mapping); + // --- + + scat_set_xms_bound(0); + scat_shadow_state_update(); +} diff --git a/src/scat.h b/src/scat.h new file mode 100644 index 000000000..1fee0cee3 --- /dev/null +++ b/src/scat.h @@ -0,0 +1,22 @@ +#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 +#define SCAT_VERSION 0x40 +#define SCAT_CLOCK_CONTROL 0x41 +#define SCAT_PERIPHERAL_CONTROL 0x44 +#define SCAT_MISCELLANEOUS_STATUS 0x45 +#define SCAT_POWER_MANAGEMENT 0x46 +#define SCAT_ROM_ENABLE 0x48 +#define SCAT_RAM_WRITE_PROTECT 0x49 +#define SCAT_SHADOW_RAM_ENABLE_1 0x4A +#define SCAT_SHADOW_RAM_ENABLE_2 0x4B +#define SCAT_SHADOW_RAM_ENABLE_3 0x4C +#define SCAT_DRAM_CONFIGURATION 0x4D +#define SCAT_EXTENDED_BOUNDARY 0x4E +#define SCAT_EMS_CONTROL 0x4F + +typedef struct scat_t +{ + uint8_t regs_2x8; + uint8_t regs_2x9; +} scat_t; + +void scat_init(); diff --git a/src/scsi_cmds.h b/src/scsi_cmds.h new file mode 100644 index 000000000..c27351c3c --- /dev/null +++ b/src/scsi_cmds.h @@ -0,0 +1,90 @@ +/* ATAPI/SCSI Commands */ +#define TEST_UNIT_READY 0x00 +#define REQUEST_SENSE 0x03 +#define READ_6 0x08 +#define INQUIRY 0x12 +#define MODE_SELECT 0x15 +#define MODE_SENSE 0x1a /*actually MODE_SENSE_6 but I want to match QEMU's scheme*/ +#define START_STOP 0x1b /*LOAD_UNLOAD is the same*/ +#define ALLOW_MEDIUM_REMOVAL 0x1e +#define READ_CAPACITY_10 0x25 +#define READ_10 0x28 +#define SEEK_10 0x2b +#define READ_SUBCHANNEL 0x42 /*unimplemented on QEMU, so I came up with this name for this command*/ +#define READ_TOC 0x43 +#define READ_HEADER 0x44 /*unimplemented on QEMU, so I came up with this name for this command*/ +#define PLAY_AUDIO_10 0x45 +#define GET_CONFIGURATION 0x46 +#define PLAY_AUDIO_MSF 0x47 +#define GET_EVENT_NOTIFICATION 0x4a +#define PAUSE_RESUME 0x4b +#define STOP_PLAY_SCAN 0x4e +#define READ_DISC_INFORMATION 0x51 +#define MODE_SELECT_10 0x55 +#define MODE_SENSE_10 0x5a +#define PLAY_AUDIO_12 0xa5 /*deprecated*/ +#define READ_12 0xa8 +#define READ_DVD_STRUCTURE 0xad +#define SET_CD_SPEED 0xbb +#define MECHANISM_STATUS 0xbd +#define READ_CD 0xbe +#define SEND_DVD_STRUCTURE 0xbf + +/* SCSI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* SCSI Additional Sense Codes */ +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_MEDIUM_NOT_PRESENT 0x3a + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* + * SCSI Status codes +*/ +#define GOOD 0x00 +#define CHECK_CONDITION 0x02 +#define CONDITION_GOOD 0x04 +#define BUSY 0x08 +#define INTERMEDIATE_GOOD 0x10 +#define INTERMEDIATE_C_GOOD 0x14 +#define RESERVATION_CONFLICT 0x18 +#define COMMAND_TERMINATED 0x22 +#define TASK_SET_FULL 0x28 +#define ACA_ACTIVE 0x30 +#define TASK_ABORTED 0x40 + +#define STATUS_MASK 0x3e + +/* Event notification classes for GET EVENT STATUS NOTIFICATION */ +#define GESN_NO_EVENTS 0 +#define GESN_OPERATIONAL_CHANGE 1 +#define GESN_POWER_MANAGEMENT 2 +#define GESN_EXTERNAL_REQUEST 3 +#define GESN_MEDIA 4 +#define GESN_MULTIPLE_HOSTS 5 +#define GESN_DEVICE_BUSY 6 + +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +#define CHECK_READY 2 +#define ALLOW_UA 1 \ No newline at end of file diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 000000000..2280ed129 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,292 @@ +#include "ibm.h" +#include "io.h" +#include "mouse.h" +#include "pic.h" +#include "serial.h" +#include "timer.h" + +enum +{ + SERIAL_INT_LSR = 1, + SERIAL_INT_RECEIVE = 2, + SERIAL_INT_TRANSMIT = 4, + SERIAL_INT_MSR = 8 +}; + +SERIAL serial1, serial2; + +int mousepos=-1; +int mousedelay; + +void serial_reset() +{ + serial1.iir = serial1.ier = serial1.lcr = 0; + serial2.iir = serial2.ier = serial2.lcr = 0; + mousedelay = 0; + serial1.fifo_read = serial1.fifo_write = 0; + serial2.fifo_read = serial2.fifo_write = 0; +} + +void serial_update_ints(SERIAL *serial) +{ + int stat = 0; + + serial->iir = 1; + + if ((serial->ier & 4) && (serial->int_status & SERIAL_INT_LSR)) /*Line status interrupt*/ + { + stat = 1; + serial->iir = 6; + } + else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Recieved data available*/ + { + stat = 1; + serial->iir = 4; + } + else if ((serial->ier & 2) && (serial->int_status & SERIAL_INT_TRANSMIT)) /*Transmit data empty*/ + { + stat = 1; + serial->iir = 2; + } + else if ((serial->ier & 8) && (serial->int_status & SERIAL_INT_MSR)) /*Modem status interrupt*/ + { + stat = 1; + serial->iir = 0; + } + + if (stat && ((serial->mctrl & 8) || PCJR)) + picintlevel(1 << serial->irq); + else + picintc(1 << serial->irq); +} + +void serial_write_fifo(SERIAL *serial, uint8_t dat) +{ +// pclog("serial_write_fifo %02X\n", serial->lsr); + serial->fifo[serial->fifo_write] = dat; + serial->fifo_write = (serial->fifo_write + 1) & 0xFF; + if (!(serial->lsr & 1)) + { + serial->lsr |= 1; + serial->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(serial); + } +} + +uint8_t serial_read_fifo(SERIAL *serial) +{ + if (serial->fifo_read != serial->fifo_write) + { + serial->dat = serial->fifo[serial->fifo_read]; + serial->fifo_read = (serial->fifo_read + 1) & 0xFF; + } + return serial->dat; +} + +void serial_write(uint16_t addr, uint8_t val, void *p) +{ + SERIAL *serial = (SERIAL *)p; +// pclog("Write serial %03X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr&7) + { + case 0: + if (serial->lcr & 0x80) + { + serial->dlab1 = val; + return; + } + serial->thr = val; + serial->lsr |= 0x20; + serial->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + if (serial->mctrl & 0x10) + { + serial_write_fifo(serial, val); + } + break; + case 1: + if (serial->lcr & 0x80) + { + serial->dlab2 = val; + return; + } + serial->ier = val & 0xf; + serial_update_ints(serial); + break; + case 3: + serial->lcr = val; + break; + case 4: + if ((val & 2) && !(serial->mctrl & 2)) + { + if (serial->rcr_callback) + serial->rcr_callback(serial); +// pclog("RCR raised! sending M\n"); + } + serial->mctrl = val; + if (val & 0x10) + { + uint8_t new_msr; + + new_msr = (val & 0x0c) << 4; + new_msr |= (val & 0x02) ? 0x10: 0; + new_msr |= (val & 0x01) ? 0x20: 0; + + if ((serial->msr ^ new_msr) & 0x10) + new_msr |= 0x01; + if ((serial->msr ^ new_msr) & 0x20) + new_msr |= 0x02; + if ((serial->msr ^ new_msr) & 0x80) + new_msr |= 0x08; + if ((serial->msr & 0x40) && !(new_msr & 0x40)) + new_msr |= 0x04; + + serial->msr = new_msr; + } + break; + case 5: + serial->lsr = val; + if (serial->lsr & 0x01) + serial->int_status |= SERIAL_INT_RECEIVE; + if (serial->lsr & 0x1e) + serial->int_status |= SERIAL_INT_LSR; + if (serial->lsr & 0x20) + serial->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + break; + case 6: + serial->msr = val; + if (serial->msr & 0x0f) + serial->int_status |= SERIAL_INT_MSR; + serial_update_ints(serial); + break; + case 7: + serial->scratch = val; + break; + } +} + +uint8_t serial_read(uint16_t addr, void *p) +{ + SERIAL *serial = (SERIAL *)p; + uint8_t temp = 0; +// pclog("Read serial %03X %04X(%08X):%04X %i %i ", addr, CS, cs, pc, mousedelay, ins); + switch (addr&7) + { + case 0: + if (serial->lcr & 0x80) + { + temp = serial->dlab1; + break; + } + + serial->lsr &= ~1; + serial->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(serial); + temp = serial_read_fifo(serial); + if (serial->fifo_read != serial->fifo_write) + serial->recieve_delay = 1000 * TIMER_USEC; + break; + case 1: + if (serial->lcr & 0x80) + temp = serial->dlab2; + else + temp = serial->ier; + break; + case 2: + temp = serial->iir; + if ((temp & 0xe) == 2) + { + serial->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + } + break; + case 3: + temp = serial->lcr; + break; + case 4: + temp = serial->mctrl; + break; + case 5: + if (serial->lsr & 0x20) + serial->lsr |= 0x40; + serial->lsr |= 0x20; + temp = serial->lsr; + if (serial->lsr & 0x1f) + serial->lsr &= ~0x1e; +// serial.lsr |= 0x60; + serial->int_status &= ~SERIAL_INT_LSR; + serial_update_ints(serial); + break; + case 6: + temp = serial->msr; + serial->msr &= ~0x0f; + serial->int_status &= ~SERIAL_INT_MSR; + serial_update_ints(serial); + break; + case 7: + temp = serial->scratch; + break; + } +// pclog("%02X\n",temp); + return temp; +} + +void serial_recieve_callback(void *p) +{ + SERIAL *serial = (SERIAL *)p; + + serial->recieve_delay = 0; + + if (serial->fifo_read != serial->fifo_write) + { + serial->lsr |= 1; + serial->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(serial); + } +} + +/*Tandy might need COM1 at 2f8*/ +void serial1_init(uint16_t addr, int irq) +{ + memset(&serial1, 0, sizeof(serial1)); + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + serial1.irq = irq; + serial1.rcr_callback = NULL; + timer_add(serial_recieve_callback, &serial1.recieve_delay, &serial1.recieve_delay, &serial1); +} +void serial1_set(uint16_t addr, int irq) +{ + serial1_remove(); + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + serial1.irq = irq; +} +void serial1_remove() +{ + io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); +} + +void serial2_init(uint16_t addr, int irq) +{ + memset(&serial2, 0, sizeof(serial2)); + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + serial2.irq = irq; + serial2.rcr_callback = NULL; + timer_add(serial_recieve_callback, &serial2.recieve_delay, &serial2.recieve_delay, &serial2); +} +void serial2_set(uint16_t addr, int irq) +{ + serial2_remove(); + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + serial2.irq = irq; +} +void serial2_remove() +{ + io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); +} diff --git a/src/serial.h b/src/serial.h new file mode 100644 index 000000000..ef04b1f07 --- /dev/null +++ b/src/serial.h @@ -0,0 +1,28 @@ +void serial1_init(uint16_t addr, int irq); +void serial2_init(uint16_t addr, int irq); +void serial1_set(uint16_t addr, int irq); +void serial2_set(uint16_t addr, int irq); +void serial1_remove(); +void serial2_remove(); +void serial_reset(); + +struct SERIAL; + +typedef struct +{ + uint8_t lsr,thr,mctrl,rcr,iir,ier,lcr,msr; + uint8_t dlab1,dlab2; + uint8_t dat; + uint8_t int_status; + uint8_t scratch; + + int irq; + + void (*rcr_callback)(void *p); + uint8_t fifo[256]; + int fifo_read, fifo_write; + + int recieve_delay; +} SERIAL; + +extern SERIAL serial1, serial2; diff --git a/src/sio.c b/src/sio.c new file mode 100644 index 000000000..582874086 --- /dev/null +++ b/src/sio.c @@ -0,0 +1,75 @@ +/*PRD format : + + word 0 - base address + word 1 - bits 1 - 15 = byte count, bit 31 = end of transfer +*/ +#include + +#include "ibm.h" +#include "ide.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "sio.h" + +static uint8_t card_sio[256]; + +void sio_write(int func, int addr, uint8_t val, void *priv) +{ +// pclog("sio_write: func=%d addr=%02x val=%02x %04x:%08x\n", func, addr, val, CS, pc); + + if ((addr & 0xff) < 4) return; + + if (func > 0) + return; + + if (func == 0) + { + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + } + card_sio[addr] = val; + } +} + +uint8_t sio_read(int func, int addr, void *priv) +{ +// pclog("sio_read: func=%d addr=%02x %04x:%08x\n", func, addr, CS, pc); + + if (func > 0) + return 0xff; + + return card_sio[addr]; +} + +void sio_init(int card) +{ + pci_add_specific(card, sio_read, sio_write, NULL); + + memset(card_sio, 0, 256); + card_sio[0x00] = 0x86; card_sio[0x01] = 0x80; /*Intel*/ + card_sio[0x02] = 0x84; card_sio[0x03] = 0x04; /*82378ZB (SIO)*/ + card_sio[0x04] = 0x07; card_sio[0x05] = 0x00; + card_sio[0x06] = 0x00; card_sio[0x07] = 0x02; + card_sio[0x08] = 0x00; /*A0 stepping*/ + card_sio[0x40] = 0x20; + card_sio[0x42] = 0x24; + card_sio[0x45] = 0x10; + card_sio[0x46] = 0x0F; + card_sio[0x48] = 0x01; + card_sio[0x4A] = 0x10; + card_sio[0x4B] = 0x0F; + card_sio[0x4C] = 0x56; + card_sio[0x4D] = 0x40; + card_sio[0x4E] = 0x07; + card_sio[0x4F] = 0x4F; + card_sio[0x60] = card_sio[0x61] = card_sio[0x62] = card_sio[0x63] = 0x80; + card_sio[0x80] = 0x78; + card_sio[0xA0] = 0x08; + card_sio[0xA8] = 0x0F; +} diff --git a/src/sio.h b/src/sio.h new file mode 100644 index 000000000..a17f4ffb8 --- /dev/null +++ b/src/sio.h @@ -0,0 +1 @@ +void sio_init(int card); diff --git a/src/sis496.c b/src/sis496.c new file mode 100644 index 000000000..5c350fd86 --- /dev/null +++ b/src/sis496.c @@ -0,0 +1,127 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "sis496.h" + +typedef struct sis496_t +{ + uint8_t pci_conf[256]; +} sis496_t; + +void sis496_recalcmapping(sis496_t *sis496) +{ + int c; + + for (c = 0; c < 8; c++) + { + uint32_t base = 0xc0000 + (c << 15); + if (sis496->pci_conf[0x44] & (1 << c)) + { + switch (sis496->pci_conf[0x45] & 3) + { + case 0: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 1: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } + else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); + shadowbios = (sis496->pci_conf[0x44] & 0xf0); +} + +void sis496_write(int func, int addr, uint8_t val, void *p) +{ + sis496_t *sis496 = (sis496_t *)p; + //pclog("sis496_write : addr=%02x val=%02x\n", addr, val); + switch (addr) + { + case 0x44: /*Shadow configure*/ + if ((sis496->pci_conf[0x44] & val) ^ 0xf0) + { + sis496->pci_conf[0x44] = val; + sis496_recalcmapping(sis496); + } + break; + case 0x45: /*Shadow configure*/ + if ((sis496->pci_conf[0x45] & val) ^ 0x01) + { + sis496->pci_conf[0x45] = val; + sis496_recalcmapping(sis496); + } + break; + } + + if ((addr >= 4 && addr < 8) || addr >= 0x40) + sis496->pci_conf[addr] = val; +} + +uint8_t sis496_read(int func, int addr, void *p) +{ + sis496_t *sis496 = (sis496_t *)p; + + return sis496->pci_conf[addr]; +} + +void *sis496_init() +{ + sis496_t *sis496 = malloc(sizeof(sis496_t)); + memset(sis496, 0, sizeof(sis496_t)); + + pci_add_specific(5, sis496_read, sis496_write, sis496); + + sis496->pci_conf[0x00] = 0x39; /*SiS*/ + sis496->pci_conf[0x01] = 0x10; + sis496->pci_conf[0x02] = 0x96; /*496/497*/ + sis496->pci_conf[0x03] = 0x04; + + sis496->pci_conf[0x04] = 7; + sis496->pci_conf[0x05] = 0; + + sis496->pci_conf[0x06] = 0x80; + sis496->pci_conf[0x07] = 0x02; + + sis496->pci_conf[0x08] = 2; /*Device revision*/ + + sis496->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis496->pci_conf[0x0a] = 0x00; + sis496->pci_conf[0x0b] = 0x06; + + sis496->pci_conf[0x0e] = 0x00; /*Single function device*/ + + return sis496; +} + +void sis496_close(void *p) +{ + sis496_t *sis496 = (sis496_t *)p; + + free(sis496); +} + +device_t sis496_device = +{ + "SiS 496/497", + 0, + sis496_init, + sis496_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sis496.h b/src/sis496.h new file mode 100644 index 000000000..c5bbac2b1 --- /dev/null +++ b/src/sis496.h @@ -0,0 +1 @@ +extern device_t sis496_device; diff --git a/src/sis50x.c b/src/sis50x.c new file mode 100644 index 000000000..817d7ba04 --- /dev/null +++ b/src/sis50x.c @@ -0,0 +1,288 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "sis50x.h" + +typedef struct sis501_t +{ + uint8_t pci_conf[256]; + uint8_t turbo_reg; +} sis501_t; + +typedef struct sis503_t +{ + uint8_t pci_conf[256]; +} sis503_t; + +typedef struct sis50x_t +{ + uint8_t isa_conf[12]; + uint8_t reg; +} sis50x_t; + +void sis501_recalcmapping(sis501_t *sis501) +{ + int c, d; + + for (c = 0; c < 1; c++) + { + for (d = 0; d < 4; d++) + { + // uint32_t base = (((2 - c) << 16) + 0xc0000) + (d << 14); + uint32_t base = 0xe0000 + (d << 14); + if (sis501->pci_conf[0x54 + c] & (1 << (d + 4))) + { + switch (sis501->pci_conf[0x53] & 0x60) + { + case 0x00: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x20: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x40: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x60: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } + else + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + + flushmmucache(); + shadowbios = 1; +} + +void sis501_write(int func, int addr, uint8_t val, void *p) +{ + sis501_t *sis501 = (sis501_t *)p; + //pclog("sis501_write : addr=%02x val=%02x\n", addr, val); + switch (addr) + { + case 0x54: /*Shadow configure*/ + if ((sis501->pci_conf[0x54] & val) ^ 0xf0) + { + sis501->pci_conf[0x54] = val; + sis501_recalcmapping(sis501); + } + break; + } + + if ((addr >= 4 && addr < 8) || addr >= 0x40) + sis501->pci_conf[addr] = val; +} + +void sis501_turbo_write(uint16_t port, uint8_t val, void *priv) +{ + sis501_t *sis501 = (sis501_t *)priv; + + uint8_t valxor = val ^ sis501->turbo_reg; + + sis501->turbo_reg = val; + + if ((val & 4) && (valxor & 4)) + { + if (sis501->turbo_reg & 2) + resetpchard(); + else + softresetx86(); + } +} + +void sis503_write(int func, int addr, uint8_t val, void *p) +{ + sis503_t *sis503 = (sis503_t *)p; + //pclog("sis503_write : addr=%02x val=%02x\n", addr, val); + + if ((addr >= 4 && addr < 8) || addr >= 0x0f) + sis503->pci_conf[addr] = val; +} + +void sis50x_write(uint16_t port, uint8_t val, void *priv) +{ + sis50x_t *sis50x = (sis50x_t *)priv; + + if (port & 1) + { + if (sis50x->reg <= 0xB) sis50x->isa_conf[sis50x->reg] = val; + } + else + { + sis50x->reg = val; + } +} + +uint8_t sis501_read(int func, int addr, void *p) +{ + sis501_t *sis501 = (sis501_t *)p; + + return sis501->pci_conf[addr]; +} + +uint8_t sis501_turbo_read(uint16_t port, void *priv) +{ + sis501_t *sis501 = (sis501_t *)priv; + + return sis501->turbo_reg; +} + +uint8_t sis503_read(int func, int addr, void *p) +{ + sis503_t *sis503 = (sis503_t *)p; + + return sis503->pci_conf[addr]; +} + +uint8_t sis50x_read(uint16_t port, void *priv) +{ + sis50x_t *sis50x = (sis50x_t *)priv; + + if (port & 1) + { + if (sis50x->reg <= 0xB) + return sis50x->isa_conf[sis50x->reg]; + else + return 0xff; + } + else + { + return sis50x->reg; + } +} + +void *sis501_init() +{ + sis501_t *sis501 = malloc(sizeof(sis501_t)); + memset(sis501, 0, sizeof(sis501_t)); + + // io_sethandler(0x0cf9, 0x0001, sis501_turbo_read, NULL, NULL, sis501_turbo_write, NULL, NULL, sis501); + + // pci_add_specific(5, sis501_read, sis501_write, sis501); + pci_add_specific(0, sis501_read, sis501_write, sis501); + + sis501->pci_conf[0x00] = 0x39; /*SiS*/ + sis501->pci_conf[0x01] = 0x10; + sis501->pci_conf[0x02] = 0x06; /*501/502*/ + sis501->pci_conf[0x03] = 0x04; + + sis501->pci_conf[0x04] = 7; + sis501->pci_conf[0x05] = 0; + + sis501->pci_conf[0x06] = 0x80; + sis501->pci_conf[0x07] = 0x02; + + sis501->pci_conf[0x08] = 0; /*Device revision*/ + + sis501->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis501->pci_conf[0x0a] = 0x00; + sis501->pci_conf[0x0b] = 0x06; + + sis501->pci_conf[0x0e] = 0x00; /*Single function device*/ + + shadowbios = 1; + + return sis501; +} + +void *sis503_init() +{ + sis503_t *sis503 = malloc(sizeof(sis503_t)); + memset(sis503, 0, sizeof(sis503_t)); + + // pci_add_specific(6, sis503_read, sis503_write, sis503); + pci_add_specific(1, sis503_read, sis503_write, sis503); + + sis503->pci_conf[0x00] = 0x39; /*SiS*/ + sis503->pci_conf[0x01] = 0x10; + sis503->pci_conf[0x02] = 0x08; /*503*/ + sis503->pci_conf[0x03] = 0x00; + + sis503->pci_conf[0x04] = 7; + sis503->pci_conf[0x05] = 0; + + sis503->pci_conf[0x06] = 0x80; + sis503->pci_conf[0x07] = 0x02; + + sis503->pci_conf[0x08] = 0; /*Device revision*/ + + sis503->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis503->pci_conf[0x0a] = 0x01; + sis503->pci_conf[0x0b] = 0x06; + + sis503->pci_conf[0x0e] = 0x00; /*Single function device*/ + + return sis503; +} + +void *sis50x_init() +{ + sis50x_t *sis50x = malloc(sizeof(sis50x_t)); + memset(sis50x, 0, sizeof(sis50x_t)); + + io_sethandler(0x22, 0x0002, sis50x_read, NULL, NULL, sis50x_write, NULL, NULL, sis50x); +} + +void sis501_close(void *p) +{ + sis501_t *sis501 = (sis501_t *)p; + + free(sis501); +} + +void sis503_close(void *p) +{ + sis503_t *sis503 = (sis503_t *)p; + + free(sis503); +} + +void sis50x_close(void *p) +{ + sis50x_t *sis50x = (sis50x_t *)p; + + free(sis50x); +} + +device_t sis501_device = +{ + "SiS 501/502", + 0, + sis501_init, + sis501_close, + NULL, + NULL, + NULL, + NULL +}; + +device_t sis503_device = +{ + "SiS 503", + 0, + sis503_init, + sis503_close, + NULL, + NULL, + NULL, + NULL +}; + +device_t sis50x_device = +{ + "SiS 50x ISA", + 0, + sis50x_init, + sis50x_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sis50x.h b/src/sis50x.h new file mode 100644 index 000000000..81e898980 --- /dev/null +++ b/src/sis50x.h @@ -0,0 +1,3 @@ +extern device_t sis501_device; +extern device_t sis503_device; +extern device_t sis50x_device; diff --git a/src/sis85c471.c b/src/sis85c471.c new file mode 100644 index 000000000..e38936da1 --- /dev/null +++ b/src/sis85c471.c @@ -0,0 +1,228 @@ +/* + SiS sis85c471 Super I/O Chip + Used by Batman's Revenge +*/ + +#include "ibm.h" +#include "ide.h" + +#include "fdc.h" +#include "fdd.h" +#include "io.h" +#include "lpt.h" +#include "mouse_serial.h" +#include "serial.h" +#include "sis85c471.h" + +static int sis85c471_curreg; +static uint8_t sis85c471_regs[39]; + +void sis85c471_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + int temp; + uint8_t x; + // pclog("sis85c471_write : port=%04x reg %02X = %02X\n", port, sis85c471_curreg, val); + + if (index) + { + if ((val >= 0x50) && (val <= 0x76)) sis85c471_curreg = val; + return; + } + else + { + if ((sis85c471_curreg < 0x50) || (sis85c471_curreg > 0x76)) return; + x = val ^ sis85c471_regs[sis85c471_curreg - 0x50]; + /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ + if (sis85c471_curreg != 0x52) sis85c471_regs[sis85c471_curreg - 0x50] = val; + goto process_value; + } + return; + +process_value: + switch(sis85c471_curreg) + { + case 0x73: +#if 0 + if (x & 0x40) + { + if (val & 0x40) + ide_pri_enable(); + else + ide_pri_disable(); + } +#endif + + if (x & 0x20) + { + if (val & 0x20) + { + serial1_init(0x3f8, 4); + serial2_init(0x2f8, 3); + mouse_serial_init(); + } + else + { + serial1_remove(); + serial2_remove(); + } + } + + if (x & 0x10) + { + if (val & 0x10) + lpt1_init(0x378); + else + lpt1_remove(); + } + + break; + } + sis85c471_curreg = 0; +} + +uint8_t sis85c471_read(uint16_t port, void *priv) +{ + // pclog("sis85c471_read : port=%04x reg %02X\n", port, sis85c471_curreg); + uint8_t index = (port & 1) ? 0 : 1; + uint8_t temp; + + if (index) + return sis85c471_curreg; + else + if ((sis85c471_curreg >= 0x50) && (sis85c471_curreg <= 0x76)) + { + temp = sis85c471_regs[sis85c471_curreg - 0x50]; + sis85c471_curreg = 0; + return temp; + } + else + return 0xFF; +} + +void sis85c471_init() +{ + int i = 0; + + // pclog("SiS 85c471 Init\n"); + + // ide_sec_disable(); + lpt2_remove(); + + sis85c471_curreg = 0; + for (i = 0; i < 0x27; i++) + { + sis85c471_regs[i] = 0; + } + sis85c471_regs[9] = 0x40; + switch (mem_size) + { + case 0: + case 1: + sis85c471_regs[9] |= 0; + break; + case 2: + case 3: + sis85c471_regs[9] |= 1; + break; + case 4: + sis85c471_regs[9] |= 2; + break; + case 5: + sis85c471_regs[9] |= 0x20; + break; + case 6: + case 7: + sis85c471_regs[9] |= 9; + break; + case 8: + case 9: + sis85c471_regs[9] |= 4; + break; + case 10: + case 11: + sis85c471_regs[9] |= 5; + break; + case 12: + case 13: + case 14: + case 15: + sis85c471_regs[9] |= 0xB; + break; + case 16: + sis85c471_regs[9] |= 0x13; + break; + case 17: + sis85c471_regs[9] |= 0x21; + break; + case 18: + case 19: + sis85c471_regs[9] |= 6; + break; + case 20: + case 21: + case 22: + case 23: + sis85c471_regs[9] |= 0xD; + break; + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + sis85c471_regs[9] |= 0xE; + break; + case 32: + case 33: + case 34: + case 35: + sis85c471_regs[9] |= 0x1B; + break; + case 36: + case 37: + case 38: + case 39: + sis85c471_regs[9] |= 0xF; + break; + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + sis85c471_regs[9] |= 0x17; + break; + case 48: + sis85c471_regs[9] |= 0x1E; + break; + default: + if (mem_size < 64) + { + sis85c471_regs[9] |= 0x1E; + } + else if ((mem_size >= 65) && (mem_size < 68)) + { + sis85c471_regs[9] |= 0x22; + } + else + { + sis85c471_regs[9] |= 0x24; + } + break; + } + + sis85c471_regs[0x11] = 9; + sis85c471_regs[0x12] = 0xFF; + sis85c471_regs[0x23] = 0xF0; + sis85c471_regs[0x26] = 1; + + fdc_update_densel_polarity(1); + fdc_update_densel_force(0); + fdd_swap = 0; + io_sethandler(0x0022, 0x0002, sis85c471_read, NULL, NULL, sis85c471_write, NULL, NULL, NULL); +} diff --git a/src/sis85c471.h b/src/sis85c471.h new file mode 100644 index 000000000..79ebe5dbf --- /dev/null +++ b/src/sis85c471.h @@ -0,0 +1 @@ +extern void sis85c471_init(); diff --git a/src/slirp/COPYRIGHT.txt b/src/slirp/COPYRIGHT.txt new file mode 100644 index 000000000..62ccebae1 --- /dev/null +++ b/src/slirp/COPYRIGHT.txt @@ -0,0 +1,61 @@ +Slirp was written by Danny Gasparovski. +Copyright (c), 1995,1996 All Rights Reserved. + +Slirp is maintained by Kelly Price + +Slirp is free software; "free" as in you don't have to pay for it, and you +are free to do whatever you want with it. I do not accept any donations, +monetary or otherwise, for Slirp. Instead, I would ask you to pass this +potential donation to your favorite charity. In fact, I encourage +*everyone* who finds Slirp useful to make a small donation to their +favorite charity (for example, GreenPeace). This is not a requirement, but +a suggestion from someone who highly values the service they provide. + +The copyright terms and conditions: + +---BEGIN--- + + Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + DANNY GASPAROVSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---END--- + +This basically means you can do anything you want with the software, except +1) call it your own, and 2) claim warranty on it. There is no warranty for +this software. None. Nada. If you lose a million dollars while using +Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. + +If these conditions cannot be met due to legal restrictions (E.g. where it +is against the law to give out Software without warranty), you must cease +using the software and delete all copies you have. + +Slirp uses code that is copyrighted by the following people/organizations: + +Juha Pirkola. +Gregory M. Christy. +The Regents of the University of California. +Carnegie Mellon University. +The Australian National University. +RSA Data Security, Inc. + +Please read the top of each source file for the details on the various +copyrights. \ No newline at end of file diff --git a/src/slirp/Makefile b/src/slirp/Makefile new file mode 100644 index 000000000..275c054d2 --- /dev/null +++ b/src/slirp/Makefile @@ -0,0 +1,26 @@ +CC=gcc +CFLAGS=-I. -O2 -Wall +DEPS = bootp.h config-host.h config.h ctl.h \ + debug.h icmp_var.h if.h ip.h \ + ip_icmp.h libslirp.h main.h mbuf.h \ + misc.h queue.h sbuf.h slirp.h \ + slirp_config.h socket.h tcp.h tcpip.h \ + tcp_timer.h tcp_var.h tftp.h udp.h + +OBJ = bootp.o cksum.o debug.o if.o ip_icmp.o \ + ip_input.o ip_output.o mbuf.o misc.o queue.o \ + sbuf.o slirp.o socket.o tcp_input.o tcp_output.o \ + tcp_subr.o tcp_timer.o tftp.o udp.o + +%.o: %.c $(DEPS) + $(CC) $(CFLAGS) -c $< -o $@ + +default: libslirp.a + +clean: + rm -f $(OBJ) + rm -f libslirp.a + +libslirp.a: $(OBJ) + ar rcs $@ $^ + ranlib $@ \ No newline at end of file diff --git a/src/slirp/VERSION.txt b/src/slirp/VERSION.txt new file mode 100644 index 000000000..0dd1c2b2b --- /dev/null +++ b/src/slirp/VERSION.txt @@ -0,0 +1 @@ +qemu 0.9.0 (2007/02/05) \ No newline at end of file diff --git a/src/slirp/bootp.c b/src/slirp/bootp.c new file mode 100644 index 000000000..9cbca7520 --- /dev/null +++ b/src/slirp/bootp.c @@ -0,0 +1,242 @@ +/* + * QEMU BOOTP/DHCP server + * + * 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 "slirp.h" + +/* XXX: only DHCP is supported */ + +#define NB_ADDR 16 + +#define START_ADDR 15 + +#define LEASE_TIME (24 * 3600) + +typedef struct { + uint8_t allocated; + uint8_t macaddr[6]; +} BOOTPClient; + +BOOTPClient bootp_clients[NB_ADDR]; + +static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; + +static BOOTPClient *get_new_addr(struct in_addr *paddr) +{ + BOOTPClient *bc; + int i; + + for(i = 0; i < NB_ADDR; i++) { + if (!bootp_clients[i].allocated) + goto found; + } + return NULL; + found: + bc = &bootp_clients[i]; + bc->allocated = 1; + paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + return bc; +} + +static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr) +{ + BOOTPClient *bc; + int i; + + for(i = 0; i < NB_ADDR; i++) { + if (!memcmp(macaddr, bootp_clients[i].macaddr, 6)) + goto found; + } + return NULL; + found: + bc = &bootp_clients[i]; + bc->allocated = 1; + paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + return bc; +} + +static void dhcp_decode(const uint8_t *buf, int size, + int *pmsg_type) +{ + const uint8_t *p, *p_end; + int len, tag; + + *pmsg_type = 0; + + p = buf; + p_end = buf + size; + if (size < 5) + return; + if (memcmp(p, rfc1533_cookie, 4) != 0) + return; + p += 4; + while (p < p_end) { + tag = p[0]; + if (tag == RFC1533_PAD) { + p++; + } else if (tag == RFC1533_END) { + break; + } else { + p++; + if (p >= p_end) + break; + len = *p++; + + switch(tag) { + case RFC2132_MSG_TYPE: + if (len >= 1) + *pmsg_type = p[0]; + break; + default: + break; + } + p += len; + } + } +} + +static void bootp_reply(struct bootp_t *bp) +{ + BOOTPClient *bc; + struct SLIRPmbuf *m; + struct bootp_t *rbp; + struct sockaddr_in saddr, daddr; + struct in_addr dns_addr; + int dhcp_msg_type, val; + uint8_t *q; + + /* extract exact DHCP msg type */ + dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); + + if (dhcp_msg_type == 0) + dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ + + if (dhcp_msg_type != DHCPDISCOVER && + dhcp_msg_type != DHCPREQUEST) + return; + /* XXX: this is a hack to get the client mac address */ + memcpy(client_ethaddr, bp->bp_hwaddr, 6); + + if ((m = m_get()) == NULL) + return; + m->m_data += if_maxlinkhdr; + rbp = (struct bootp_t *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + memset(rbp, 0, sizeof(struct bootp_t)); + + if (dhcp_msg_type == DHCPDISCOVER) { + new_addr: + bc = get_new_addr(&daddr.sin_addr); + if (!bc) + return; + memcpy(bc->macaddr, client_ethaddr, 6); + } else { + bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr); + if (!bc) { + /* if never assigned, behaves as if it was already + assigned (windows fix because it remembers its address) */ + goto new_addr; + } + } + + saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS); + saddr.sin_port = htons(BOOTP_SERVER); + + daddr.sin_port = htons(BOOTP_CLIENT); + + rbp->bp_op = BOOTP_REPLY; + rbp->bp_xid = bp->bp_xid; + rbp->bp_htype = 1; + rbp->bp_hlen = 6; + memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6); + + rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ + rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ + + q = rbp->bp_vend; + memcpy(q, rfc1533_cookie, 4); + q += 4; + + if (dhcp_msg_type == DHCPDISCOVER) { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPOFFER; + } else if (dhcp_msg_type == DHCPREQUEST) { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPACK; + } + + if (dhcp_msg_type == DHCPDISCOVER || + dhcp_msg_type == DHCPREQUEST) { + *q++ = RFC2132_SRV_ID; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_NETMASK; + *q++ = 4; + *q++ = 0xff; + *q++ = 0xff; + *q++ = 0xff; + *q++ = 0x00; + + *q++ = RFC1533_GATEWAY; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_DNS; + *q++ = 4; + dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); + memcpy(q, &dns_addr, 4); + q += 4; + + *q++ = RFC2132_LEASE_TIME; + *q++ = 4; + val = htonl(LEASE_TIME); + memcpy(q, &val, 4); + q += 4; + + if (*slirp_hostname) { + val = strlen(slirp_hostname); + *q++ = RFC1533_HOSTNAME; + *q++ = val; + memcpy(q, slirp_hostname, val); + q += val; + } + } + *q++ = RFC1533_END; + + m->m_len = sizeof(struct bootp_t) - + sizeof(struct ip) - sizeof(struct udphdr); + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); +} + +void bootp_input(struct SLIRPmbuf *m) +{ + struct bootp_t *bp = mtod(m, struct bootp_t *); + + if (bp->bp_op == BOOTP_REQUEST) { + bootp_reply(bp); + } +} diff --git a/src/slirp/bootp.h b/src/slirp/bootp.h new file mode 100644 index 000000000..b2ee26e95 --- /dev/null +++ b/src/slirp/bootp.h @@ -0,0 +1,121 @@ +/* bootp/dhcp defines */ + +#define BOOTP_SERVER 67 +#define BOOTP_CLIENT 68 + +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +#define RFC1533_COOKIE 99, 130, 83, 99 +#define RFC1533_PAD 0 +#define RFC1533_NETMASK 1 +#define RFC1533_TIMEOFFSET 2 +#define RFC1533_GATEWAY 3 +#define RFC1533_TIMESERVER 4 +#define RFC1533_IEN116NS 5 +#define RFC1533_DNS 6 +#define RFC1533_LOGSERVER 7 +#define RFC1533_COOKIESERVER 8 +#define RFC1533_LPRSERVER 9 +#define RFC1533_IMPRESSSERVER 10 +#define RFC1533_RESOURCESERVER 11 +#define RFC1533_HOSTNAME 12 +#define RFC1533_BOOTFILESIZE 13 +#define RFC1533_MERITDUMPFILE 14 +#define RFC1533_DOMAINNAME 15 +#define RFC1533_SWAPSERVER 16 +#define RFC1533_ROOTPATH 17 +#define RFC1533_EXTENSIONPATH 18 +#define RFC1533_IPFORWARDING 19 +#define RFC1533_IPSOURCEROUTING 20 +#define RFC1533_IPPOLICYFILTER 21 +#define RFC1533_IPMAXREASSEMBLY 22 +#define RFC1533_IPTTL 23 +#define RFC1533_IPMTU 24 +#define RFC1533_IPMTUPLATEAU 25 +#define RFC1533_INTMTU 26 +#define RFC1533_INTLOCALSUBNETS 27 +#define RFC1533_INTBROADCAST 28 +#define RFC1533_INTICMPDISCOVER 29 +#define RFC1533_INTICMPRESPOND 30 +#define RFC1533_INTROUTEDISCOVER 31 +#define RFC1533_INTROUTESOLICIT 32 +#define RFC1533_INTSTATICROUTES 33 +#define RFC1533_LLTRAILERENCAP 34 +#define RFC1533_LLARPCACHETMO 35 +#define RFC1533_LLETHERNETENCAP 36 +#define RFC1533_TCPTTL 37 +#define RFC1533_TCPKEEPALIVETMO 38 +#define RFC1533_TCPKEEPALIVEGB 39 +#define RFC1533_NISDOMAIN 40 +#define RFC1533_NISSERVER 41 +#define RFC1533_NTPSERVER 42 +#define RFC1533_VENDOR 43 +#define RFC1533_NBNS 44 +#define RFC1533_NBDD 45 +#define RFC1533_NBNT 46 +#define RFC1533_NBSCOPE 47 +#define RFC1533_XFS 48 +#define RFC1533_XDM 49 + +#define RFC2132_REQ_ADDR 50 +#define RFC2132_LEASE_TIME 51 +#define RFC2132_MSG_TYPE 53 +#define RFC2132_SRV_ID 54 +#define RFC2132_PARAM_LIST 55 +#define RFC2132_MAX_SIZE 57 +#define RFC2132_RENEWAL_TIME 58 +#define RFC2132_REBIND_TIME 59 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPACK 5 + +#define RFC1533_VENDOR_MAJOR 0 +#define RFC1533_VENDOR_MINOR 0 + +#define RFC1533_VENDOR_MAGIC 128 +#define RFC1533_VENDOR_ADDPARM 129 +#define RFC1533_VENDOR_ETHDEV 130 +#define RFC1533_VENDOR_HOWTO 132 +#define RFC1533_VENDOR_MNUOPTS 160 +#define RFC1533_VENDOR_SELECTION 176 +#define RFC1533_VENDOR_MOTD 184 +#define RFC1533_VENDOR_NUMOFMOTD 8 +#define RFC1533_VENDOR_IMG 192 +#define RFC1533_VENDOR_NUMOFIMG 16 + +#define RFC1533_END 255 +#define BOOTP_VENDOR_LEN 64 +#define DHCP_OPT_LEN 312 + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct bootp_t { + struct ip ip; + struct udphdr udp; + uint8_t bp_op; + uint8_t bp_htype; + uint8_t bp_hlen; + uint8_t bp_hops; + uint32_t bp_xid; + uint16_t bp_secs; + uint16_t unused; + struct in_addr bp_ciaddr; + struct in_addr bp_yiaddr; + struct in_addr bp_siaddr; + struct in_addr bp_giaddr; + uint8_t bp_hwaddr[16]; + uint8_t bp_sname[64]; + uint8_t bp_file[128]; + uint8_t bp_vend[DHCP_OPT_LEN]; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +void bootp_input(struct SLIRPmbuf *m); diff --git a/src/slirp/cksum.c b/src/slirp/cksum.c new file mode 100644 index 000000000..79df96d34 --- /dev/null +++ b/src/slirp/cksum.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 1988, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 + * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp + */ + +#include "slirp.h" + +/* + * Checksum routine for Internet Protocol family headers (Portable Version). + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * XXX Since we will never span more than 1 SLIRPmbuf, we can optimise this + */ + +#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 SLIRPmbuf *m, int len) +{ + register u_int16_t *w; + register int sum = 0; + register int mlen = 0; + int byte_swapped = 0; + + union { + u_int8_t c[2]; + u_int16_t s; + } s_util; + union { + u_int16_t s[2]; + u_int32_t l; + } l_util; + + if (m->m_len == 0) + goto cont; + w = mtod(m, u_int16_t *); + + mlen = m->m_len; + + if (len < mlen) + mlen = len; + len -= mlen; + /* + * Force to even boundary. + */ + if ((1 & (long) w) && (mlen > 0)) { + REDUCE; + sum <<= 8; + s_util.c[0] = *(u_int8_t *)w; + w = (u_int16_t *)((int8_t *)w + 1); + mlen--; + byte_swapped = 1; + } + /* + * Unroll the loop to make overhead from + * branches &c small. + */ + while ((mlen -= 32) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; + sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; + sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; + w += 16; + } + mlen += 32; + while ((mlen -= 8) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + w += 4; + } + mlen += 8; + if (mlen == 0 && byte_swapped == 0) + goto cont; + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + + if (byte_swapped) { + REDUCE; + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + s_util.c[1] = *(u_int8_t *)w; + sum += s_util.s; + mlen = 0; + } else + + mlen = -1; + } else if (mlen == -1) + s_util.c[0] = *(u_int8_t *)w; + +cont: +#ifdef SLIRP_DEBUG + if (len) { + DEBUG_ERROR((dfd, "cksum: out of data\n")); + DEBUG_ERROR((dfd, " len = %d\n", len)); + } +#endif + if (mlen == -1) { + /* The last SLIRPmbuf has odd # of bytes. Follow the + standard (the odd byte may be shifted left by 8 bits + or not as determined by endian-ness of the machine) */ + s_util.c[1] = 0; + sum += s_util.s; + } + REDUCE; + return (~sum & 0xffff); +} diff --git a/src/slirp/config-host.h b/src/slirp/config-host.h new file mode 100644 index 000000000..2983fc727 --- /dev/null +++ b/src/slirp/config-host.h @@ -0,0 +1,9 @@ +/* Automatically generated by configure - do not modify */ +#define CONFIG_QEMU_SHAREDIR "/c/Program Files/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.9.0" +#define CONFIG_UNAME_RELEASE "" diff --git a/src/slirp/config.h b/src/slirp/config.h new file mode 100644 index 000000000..d9043ae85 --- /dev/null +++ b/src/slirp/config.h @@ -0,0 +1,9 @@ +/* Automatically generated by configure - do not modify */ +#include "config-host.h" +#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-i386" +#define TARGET_ARCH "i386" +#define TARGET_I386 1 +#define USE_KQEMU 1 +#define CONFIG_SOFTMMU 1 +#define CONFIG_SDL 1 +#define HAVE_STRDUP 1 diff --git a/src/slirp/ctl.h b/src/slirp/ctl.h new file mode 100644 index 000000000..4a8576dc1 --- /dev/null +++ b/src/slirp/ctl.h @@ -0,0 +1,7 @@ +#define CTL_CMD 0 +#define CTL_EXEC 1 +#define CTL_ALIAS 2 +#define CTL_DNS 3 + +#define CTL_SPECIAL "10.0.2.0" +#define CTL_LOCAL "10.0.2.15" diff --git a/src/slirp/debug.c b/src/slirp/debug.c new file mode 100644 index 000000000..556e02672 --- /dev/null +++ b/src/slirp/debug.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * Portions copyright (c) 2000 Kelly Price. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +FILE *dfd = NULL; +#ifdef SLIRP_DEBUG +int dostats = 1; +#else +int dostats = 0; +#endif +int slirp_debug = 0; + +extern char *strerror _P((int)); + +/* Carry over one item from main.c so that the tty's restored. + * Only done when the tty being used is /dev/tty --RedWolf */ +extern struct termios slirp_tty_settings; +extern int slirp_tty_restore; + + +void +debug_init(file, dbg) + char *file; + int dbg; +{ + /* Close the old debugging file */ + if (dfd) + fclose(dfd); + + dfd = fopen(file,"w"); + if (dfd != NULL) { +#if 1 + fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION); +#endif + fprintf(dfd,"Debugging Started level %i.\r\n",dbg); + fflush(dfd); + slirp_debug = dbg; + } else { + lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n", + file, strerror(errno)); + } +} + +/* + * Dump a packet in the same format as tcpdump -x + */ +#ifdef SLIRP_DEBUG +void +dump_packet(dat, n) + void *dat; + int n; +{ + u_char *pptr = (u_char *)dat; + int j,k; + + n /= 16; + n++; + DEBUG_MISC((dfd, "PACKET DUMPED: \n")); + for(j = 0; j < n; j++) { + for(k = 0; k < 6; k++) + DEBUG_MISC((dfd, "%02x ", *pptr++)); + DEBUG_MISC((dfd, "\n")); + fflush(dfd); + } +} +#endif + +#if 0 +/* + * Statistic routines + * + * These will print statistics to the screen, the debug file (dfd), or + * a buffer, depending on "type", so that the stats can be sent over + * the link as well. + */ + +void +ttystats(ttyp) + struct ttys *ttyp; +{ + struct slirp_ifstats *is = &ttyp->ifstats; + char buff[512]; + + lprint(" \r\n"); + + if (if_comp & IF_COMPRESS) + strcpy(buff, "on"); + else if (if_comp & IF_NOCOMPRESS) + strcpy(buff, "off"); + else + strcpy(buff, "off (for now)"); + lprint("Unit %d:\r\n", ttyp->unit); + lprint(" using %s encapsulation (VJ compression is %s)\r\n", ( +#ifdef USE_PPP + ttyp->proto==PROTO_PPP?"PPP": +#endif + "SLIP"), buff); + lprint(" %d baudrate\r\n", ttyp->baud); + lprint(" interface is %s\r\n", ttyp->up?"up":"down"); + lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid); +#ifndef FULL_BOLT + lprint(" towrite is %d bytes\r\n", ttyp->towrite); +#endif + if (ttyp->zeros) + lprint(" %d zeros have been typed\r\n", ttyp->zeros); + else if (ttyp->ones) + lprint(" %d ones have been typed\r\n", ttyp->ones); + lprint("Interface stats:\r\n"); + lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes); + lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes); + lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes); + lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes); + lprint(" %6d bad input packets\r\n", is->in_mbad); +} + +void +allttystats() +{ + struct ttys *ttyp; + + for (ttyp = ttys; ttyp; ttyp = ttyp->next) + ttystats(ttyp); +} +#endif + +void +ipstats() +{ + lprint(" \r\n"); + + lprint("IP stats:\r\n"); + lprint(" %6d total packets received (%d were unaligned)\r\n", + ipstat.ips_total, ipstat.ips_unaligned); + lprint(" %6d with incorrect version\r\n", ipstat.ips_badvers); + lprint(" %6d with bad header checksum\r\n", ipstat.ips_badsum); + lprint(" %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort); + lprint(" %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall); + lprint(" %6d with bad header length\r\n", ipstat.ips_badhlen); + lprint(" %6d with bad packet length\r\n", ipstat.ips_badlen); + lprint(" %6d fragments received\r\n", ipstat.ips_fragments); + lprint(" %6d fragments dropped\r\n", ipstat.ips_fragdropped); + lprint(" %6d fragments timed out\r\n", ipstat.ips_fragtimeout); + lprint(" %6d packets reassembled ok\r\n", ipstat.ips_reassembled); + lprint(" %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented); + lprint(" %6d total outgoing fragments\r\n", ipstat.ips_ofragments); + lprint(" %6d with bad protocol field\r\n", ipstat.ips_noproto); + lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered); +} + +#if 0 +void +vjstats() +{ + lprint(" \r\n"); + + lprint("VJ compression stats:\r\n"); + + lprint(" %6d outbound packets (%d compressed)\r\n", + comp_s.sls_packets, comp_s.sls_compressed); + lprint(" %6d searches for connection stats (%d misses)\r\n", + comp_s.sls_searches, comp_s.sls_misses); + lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin); + lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin); + lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin); + lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed); +} +#endif + +void +tcpstats() +{ + lprint(" \r\n"); + + lprint("TCP stats:\r\n"); + + lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal); + lprint(" %6d data packets (%d bytes)\r\n", + tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte); + lprint(" %6d data packets retransmitted (%d bytes)\r\n", + tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte); + lprint(" %6d ack-only packets (%d delayed)\r\n", + tcpstat.tcps_sndacks, tcpstat.tcps_delack); + lprint(" %6d URG only packets\r\n", tcpstat.tcps_sndurg); + lprint(" %6d window probe packets\r\n", tcpstat.tcps_sndprobe); + lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup); + lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl); + lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin); + + lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); + lprint(" %6d acks (for %d bytes)\r\n", + tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte); + lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack); + lprint(" %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch); + lprint(" %6d packets received in sequence (%d bytes)\r\n", + tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte); + lprint(" %6d completely duplicate packets (%d bytes)\r\n", + tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte); + + lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n", + tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte); + lprint(" %6d out-of-order packets (%d bytes)\r\n", + tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte); + lprint(" %6d packets of data after window (%d bytes)\r\n", + tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin); + lprint(" %6d window probes\r\n", tcpstat.tcps_rcvwinprobe); + lprint(" %6d window update packets\r\n", tcpstat.tcps_rcvwinupd); + lprint(" %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose); + lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum); + lprint(" %6d discarded for bad header offset fields\r\n", + tcpstat.tcps_rcvbadoff); + + lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt); + lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts); + lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects); + lprint(" %6d connections closed (including %d drop)\r\n", + tcpstat.tcps_closed, tcpstat.tcps_drops); + lprint(" %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops); + lprint(" %6d segments we tried to get rtt (%d succeeded)\r\n", + tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated); + lprint(" %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo); + lprint(" %6d connections dropped by rxmt timeout\r\n", + tcpstat.tcps_timeoutdrop); + lprint(" %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo); + lprint(" %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo); + lprint(" %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe); + lprint(" %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops); + lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack); + lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat); + lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss); + + +/* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */ +/* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */ + +} + +void +udpstats() +{ + lprint(" \r\n"); + + lprint("UDP stats:\r\n"); + lprint(" %6d datagrams received\r\n", udpstat.udps_ipackets); + lprint(" %6d with packets shorter than header\r\n", udpstat.udps_hdrops); + lprint(" %6d with bad checksums\r\n", udpstat.udps_badsum); + lprint(" %6d with data length larger than packet\r\n", udpstat.udps_badlen); + lprint(" %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss); + lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets); +} + +void +icmpstats() +{ + lprint(" \r\n"); + lprint("ICMP stats:\r\n"); + lprint(" %6d ICMP packets received\r\n", icmpstat.icps_received); + lprint(" %6d were too short\r\n", icmpstat.icps_tooshort); + lprint(" %6d with bad checksums\r\n", icmpstat.icps_checksum); + lprint(" %6d with type not supported\r\n", icmpstat.icps_notsupp); + lprint(" %6d with bad type feilds\r\n", icmpstat.icps_badtype); + lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect); +} + +void +mbufstats() +{ + struct SLIRPmbuf *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(void) +{ + char buff[256]; + int n; + struct SLIRPsocket *so; + + lprint(" \r\n"); + + lprint( + "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + lprint("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + lprint("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + + } + + for (so = udb.so_next; so != &udb; so = so->so_next) { + + n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + lprint("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + lprint("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + } +} + + + +void printf_sockstats(void) +{ + char buff[256]; + int n; + struct SLIRPsocket *so; + + printf(" \r\n"); + + printf( + "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + printf("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + printf("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + + } + + for (so = udb.so_next; so != &udb; so = so->so_next) { + + n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + printf("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + printf("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + } +printf("\n\n"); +} + +//Simple code to purge and close open sockets. +//This way we can open/close/open/close.. +void purgesocks(void) +{ + struct SLIRPsocket *so; + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + closesocket(so->s); //close the socket + } +} + +#if 1 +void +slirp_exit(exit_status) + int exit_status; +{ +// struct ttys *ttyp; + + DEBUG_CALL("slirp_exit"); + DEBUG_ARG("exit_status = %d", exit_status); + + if (dostats) { + lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf; + if (!dfd) + debug_init("slirp_stats", 0xf); + lprint_arg = (char **)&dfd; + + ipstats(); + tcpstats(); + udpstats(); + icmpstats(); + mbufstats(); + sockstats(); + fclose(dfd); +// allttystats(); +// vjstats(); + } + +// for (ttyp = ttys; ttyp; ttyp = ttyp->next) +// tty_detached(ttyp, 1); + +// if (slirp_forked) { +// /* Menendez time */ +// if (kill(getppid(), SIGQUIT) < 0) +// lprint("Couldn't kill parent process %ld!\n", +// (long) getppid()); +// } + + /* Restore the terminal if we gotta */ +// if(slirp_tty_restore) +// tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */ +// exit(exit_status); + + //This will iterate though the sockets, and close them all (think redirects) + //PCem will have SLiRP open, close several times, which trips up SLiRP + //So for now I go through the sockets and close them + purgesocks(); + +} +#endif diff --git a/src/slirp/debug.h b/src/slirp/debug.h new file mode 100644 index 000000000..9a8c5e8c8 --- /dev/null +++ b/src/slirp/debug.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define PRN_STDERR 1 +#define PRN_SPRINTF 2 + +extern FILE *dfd; +extern FILE *lfd; +extern int dostats; +extern int slirp_debug; + +#define DBG_CALL 0x1 +#define DBG_MISC 0x2 +#define DBG_ERROR 0x4 +#define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR + +#ifdef SLIRP_DEBUG +#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); } +#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); } +#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); } +#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); } +#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); } + + +#else + +#define DEBUG_CALL(x) +#define DEBUG_ARG(x, y) +#define DEBUG_ARGS(x) +#define DEBUG_MISC(x) +#define DEBUG_ERROR(x) + +#endif + +void debug_init _P((char *, int)); +//void ttystats _P((struct ttys *)); +void allttystats _P((void)); +void ipstats _P((void)); +void vjstats _P((void)); +void tcpstats _P((void)); +void udpstats _P((void)); +void icmpstats _P((void)); +void mbufstats _P((void)); +void sockstats _P((void)); +void slirp_exit _P((int)); + diff --git a/src/slirp/icmp_var.h b/src/slirp/icmp_var.h new file mode 100644 index 000000000..9af222fb7 --- /dev/null +++ b/src/slirp/icmp_var.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 + * icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp + */ + +#ifndef _NETINET_ICMP_VAR_H_ +#define _NETINET_ICMP_VAR_H_ + +/* + * Variables related to this implementation + * of the internet control message protocol. + */ +struct icmpstat { +/* statistics related to input messages processed */ + u_long icps_received; /* #ICMP packets received */ + u_long icps_tooshort; /* packet < ICMP_MINLEN */ + u_long icps_checksum; /* bad checksum */ + u_long icps_notsupp; /* #ICMP packets not supported */ + u_long icps_badtype; /* #with bad type feild */ + u_long icps_reflect; /* number of responses */ +}; + +/* + * Names for ICMP sysctl objects + */ +#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */ +#define ICMPCTL_STATS 2 /* statistics (read-only) */ +#define ICMPCTL_MAXID 3 + +#define ICMPCTL_NAMES { \ + { 0, 0 }, \ + { "maskrepl", CTLTYPE_INT }, \ + { "stats", CTLTYPE_STRUCT }, \ +} + +extern struct icmpstat icmpstat; + +#endif diff --git a/src/slirp/if.c b/src/slirp/if.c new file mode 100644 index 000000000..24f1b9947 --- /dev/null +++ b/src/slirp/if.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +int if_mtu, if_mru; +int if_comp; +int if_maxlinkhdr; +int if_queued = 0; /* Number of packets queued so far */ +int if_thresh = 10; /* Number of packets queued before we start sending + * (to prevent allocing too many SLIRPmbufs) */ + +struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ +struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ +struct SLIRPmbuf *next_m; /* Pointer to next SLIRPmbuf to output */ + +#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) + +void +ifs_insque(ifm, ifmhead) + struct SLIRPmbuf *ifm, *ifmhead; +{ + ifm->ifs_next = ifmhead->ifs_next; + ifmhead->ifs_next = ifm; + ifm->ifs_prev = ifmhead; + ifm->ifs_next->ifs_prev = ifm; +} + +void +ifs_remque(ifm) + struct SLIRPmbuf *ifm; +{ + ifm->ifs_prev->ifs_next = ifm->ifs_next; + ifm->ifs_next->ifs_prev = ifm->ifs_prev; +} + +void +if_init() +{ +#if 0 + /* + * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP, + * and 8 bytes for PPP, but need to have it on an 8byte boundary + */ +#ifdef USE_PPP + if_maxlinkhdr = 48; +#else + if_maxlinkhdr = 40; +#endif +#else + /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */ + if_maxlinkhdr = 2 + 14 + 40; +#endif + if_mtu = 1500; + if_mru = 1500; + if_comp = IF_AUTOCOMP; + if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq; + if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq; + // sl_compress_init(&comp_s); + next_m = &if_batchq; +} + +#if 0 +/* + * This shouldn't be needed since the modem is blocking and + * we don't expect any signals, but what the hell.. + */ +inline int +writen(fd, bptr, n) + int fd; + char *bptr; + int n; +{ + int ret; + int total; + + /* This should succeed most of the time */ + ret = send(fd, bptr, n,0); + if (ret == n || ret <= 0) + return ret; + + /* Didn't write everything, go into the loop */ + total = ret; + while (n > total) { + ret = send(fd, bptr+total, n-total,0); + if (ret <= 0) + return ret; + total += ret; + } + return total; +} + +/* + * if_input - read() the tty, do "top level" processing (ie: check for any escapes), + * and pass onto (*ttyp->if_input) + * + * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet. + */ +#define INBUFF_SIZE 2048 /* XXX */ +void +if_input(ttyp) + struct ttys *ttyp; +{ + u_char if_inbuff[INBUFF_SIZE]; + int if_n; + + DEBUG_CALL("if_input"); + DEBUG_ARG("ttyp = %lx", (long)ttyp); + + if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0); + + DEBUG_MISC((dfd, " read %d bytes\n", if_n)); + + if (if_n <= 0) { + if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) { + if (ttyp->up) + link_up--; + tty_detached(ttyp, 0); + } + return; + } + if (if_n == 1) { + if (*if_inbuff == '0') { + ttyp->ones = 0; + if (++ttyp->zeros >= 5) + slirp_exit(0); + return; + } + if (*if_inbuff == '1') { + ttyp->zeros = 0; + if (++ttyp->ones >= 5) + tty_detached(ttyp, 0); + return; + } + } + ttyp->ones = ttyp->zeros = 0; + + (*ttyp->if_input)(ttyp, if_inbuff, if_n); +} +#endif + +/* + * if_output: Queue packet into an output queue. + * There are 2 output queue's, if_fastq and if_batchq. + * Each output queue is a doubly linked list of double linked lists + * of SLIRPmbufs, each list belonging to one "session" (socket). This + * way, we can output packets fairly by sending one packet from each + * session, instead of all the packets from one session, then all packets + * from the next session, etc. Packets on the if_fastq get absolute + * priority, but if one session hogs the link, it gets "downgraded" + * to the batchq until it runs out of packets, then it'll return + * to the fastq (eg. if the user does an ls -alR in a telnet session, + * it'll temporarily get downgraded to the batchq) + */ +void +if_output(so, ifm) + struct SLIRPsocket *so; + struct SLIRPmbuf *ifm; +{ + struct SLIRPmbuf *ifq; + int on_fastq = 1; + + DEBUG_CALL("if_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("ifm = %lx", (long)ifm); + + /* + * First remove the SLIRPmbuf from m_usedlist, + * since we're gonna use m_next and m_prev ourselves + * XXX Shouldn't need this, gotta change dtom() etc. + */ + if (ifm->m_flags & M_USEDLIST) { + remque(ifm); + ifm->m_flags &= ~M_USEDLIST; + } + + /* + * See if there's already a batchq list for this session. + * This can include an interactive session, which should go on fastq, + * but gets too greedy... hence it'll be downgraded from fastq to batchq. + * We mustn't put this packet back on the fastq (or we'll send it out of order) + * XXX add cache here? + */ + for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) { + if (so == ifq->ifq_so) { + /* A match! */ + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } + + /* No match, check which queue to put it on */ + if (so && (so->so_iptos & IPTOS_LOWDELAY)) { + ifq = if_fastq.ifq_prev; + on_fastq = 1; + /* + * Check if this packet is a part of the last + * packet's session + */ + if (ifq->ifq_so == so) { + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } else + ifq = if_batchq.ifq_prev; + + /* Create a new doubly linked list for this session */ + ifm->ifq_so = so; + ifs_init(ifm); + insque(ifm, ifq); + +diddit: + ++if_queued; + + if (so) { + /* Update *_queued */ + so->so_queued++; + so->so_nqueued++; + /* + * Check if the interactive session should be downgraded to + * the batchq. A session is downgraded if it has queued 6 + * packets without pausing, and at least 3 of those packets + * have been sent over the link + * (XXX These are arbitrary numbers, probably not optimal..) + */ + if (on_fastq && ((so->so_nqueued >= 6) && + (so->so_nqueued - so->so_queued) >= 3)) { + + /* Remove from current queue... */ + remque(ifm->ifs_next); + + /* ...And insert in the new. That'll teach ya! */ + insque(ifm->ifs_next, &if_batchq); + } + } + +#ifndef FULL_BOLT + /* + * This prevents us from malloc()ing too many SLIRPmbufs + */ + if (link_up) { + /* if_start will check towrite */ + if_start(); + } +#endif +} + +/* + * Send a packet + * We choose a packet based on it's position in the output queues; + * If there are packets on the fastq, they are sent FIFO, before + * everything else. Otherwise we choose the first packet from the + * batchq and send it. the next packet chosen will be from the session + * after this one, then the session after that one, and so on.. So, + * for example, if there are 3 ftp session's fighting for bandwidth, + * one packet will be sent from the first session, then one packet + * from the second session, then one packet from the third, then back + * to the first, etc. etc. + */ +void +if_start(void) +{ + struct SLIRPmbuf *ifm, *ifqt; + + DEBUG_CALL("if_start"); + + if (if_queued == 0) + return; /* Nothing to do */ + + again: + /* check if we can really output */ + if (!slirp_can_output()) + return; + + /* + * See which queue to get next packet from + * If there's something in the fastq, select it immediately + */ + if (if_fastq.ifq_next != &if_fastq) { + ifm = if_fastq.ifq_next; + } else { + /* Nothing on fastq, see if next_m is valid */ + if (next_m != &if_batchq) + ifm = next_m; + else + ifm = if_batchq.ifq_next; + + /* Set which packet to send on next iteration */ + next_m = ifm->ifq_next; + } + /* Remove it from the queue */ + ifqt = ifm->ifq_prev; + remque(ifm); + --if_queued; + + /* If there are more packets for this session, re-queue them */ + if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { + insque(ifm->ifs_next, ifqt); + ifs_remque(ifm); + } + + /* Update so_queued */ + if (ifm->ifq_so) { + if (--ifm->ifq_so->so_queued == 0) + /* If there's no more queued, reset nqueued */ + ifm->ifq_so->so_nqueued = 0; + } + + /* Encapsulate the packet for sending */ + if_encap((uint8_t*)ifm->m_data, ifm->m_len); + + m_free(ifm); + + if (if_queued) + goto again; +} diff --git a/src/slirp/if.h b/src/slirp/if.h new file mode 100644 index 000000000..85a5a96d2 --- /dev/null +++ b/src/slirp/if.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _IF_H_ +#define _IF_H_ + +#define IF_COMPRESS 0x01 /* We want compression */ +#define IF_NOCOMPRESS 0x02 /* Do not do compression */ +#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ +#define IF_NOCIDCOMP 0x08 /* CID compression */ + +/* Needed for FreeBSD */ +#undef if_mtu +extern int if_mtu; +extern int if_mru; /* MTU and MRU */ +extern int if_comp; /* Flags for compression */ +extern int if_maxlinkhdr; +extern int if_queued; /* Number of packets queued so far */ +extern int if_thresh; /* Number of packets queued before we start sending + * (to prevent allocing too many SLIRPmbufs) */ + +extern struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ +extern struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ +extern struct SLIRPmbuf *next_m; + +#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) + +/* Interface statistics */ +struct slirp_ifstats { + u_int out_pkts; /* Output packets */ + u_int out_bytes; /* Output bytes */ + u_int out_errpkts; /* Output Error Packets */ + u_int out_errbytes; /* Output Error Bytes */ + u_int in_pkts; /* Input packets */ + u_int in_bytes; /* Input bytes */ + u_int in_errpkts; /* Input Error Packets */ + u_int in_errbytes; /* Input Error Bytes */ + + u_int bytes_saved; /* Number of bytes that compression "saved" */ + /* ie: number of bytes that didn't need to be sent over the link + * because of compression */ + + u_int in_mbad; /* Bad incoming packets */ +}; + +#endif diff --git a/src/slirp/ip.h b/src/slirp/ip.h new file mode 100644 index 000000000..203aa750c --- /dev/null +++ b/src/slirp/ip.h @@ -0,0 +1,341 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip.h 8.1 (Berkeley) 6/10/93 + * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp + */ + +#ifndef _IP_H_ +#define _IP_H_ + +#ifdef WORDS_BIGENDIAN +# ifndef NTOHL +# define NTOHL(d) +# endif +# ifndef NTOHS +# define NTOHS(d) +# endif +# ifndef HTONL +# define HTONL(d) +# endif +# ifndef HTONS +# define HTONS(d) +# endif +#else +# ifndef NTOHL +# define NTOHL(d) ((d) = ntohl((d))) +# endif +# ifndef NTOHS +# define NTOHS(d) ((d) = ntohs((u_int16_t)(d))) +# endif +# ifndef HTONL +# define HTONL(d) ((d) = htonl((d))) +# endif +# ifndef HTONS +# define HTONS(d) ((d) = htons((u_int16_t)(d))) +# endif +#endif + +typedef u_int32_t n_long; /* long as received from the net */ + +/* + * Definitions for internet protocol version 4. + * Per RFC 791, September 1981. + */ +#define IPVERSION 4 + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +/* + * Structure of an internet header, naked of options. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ip { +#ifdef WORDS_BIGENDIAN + u_char ip_v:4, /* version */ + ip_hl:4; /* header length */ +#else + u_char ip_hl:4, /* header length */ + ip_v:4; /* version */ +#endif + u_int8_t ip_tos; /* type of service */ + u_int16_t ip_len; /* total length */ + u_int16_t ip_id; /* identification */ + u_int16_t ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* don't fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_int8_t ip_ttl; /* time to live */ + u_int8_t ip_p; /* protocol */ + u_int16_t ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) //WAS 0 +#endif + +#define IP_MAXPACKET 65535 /* maximum packet size */ + +/* + * Definitions for IP type of service (ip_tos) + */ +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 + +/* + * Definitions for options. + */ +#define IPOPT_COPIED(o) ((o)&0x80) +#define IPOPT_CLASS(o) ((o)&0x60) +#define IPOPT_NUMBER(o) ((o)&0x1f) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 /* end of option list */ +#define IPOPT_NOP 1 /* no operation */ + +#define IPOPT_RR 7 /* record packet route */ +#define IPOPT_TS 68 /* timestamp */ +#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ +#define IPOPT_LSRR 131 /* loose source route */ +#define IPOPT_SATID 136 /* satnet id */ +#define IPOPT_SSRR 137 /* strict source route */ + +/* + * Offsets to fields in options other than EOL and NOP. + */ +#define IPOPT_OPTVAL 0 /* option ID */ +#define IPOPT_OLEN 1 /* option length */ +#define IPOPT_OFFSET 2 /* offset within option */ +#define IPOPT_MINOFF 4 /* min value of above */ + +/* + * Time stamp option structure. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ip_timestamp { + u_int8_t ipt_code; /* IPOPT_TS */ + u_int8_t ipt_len; /* size of structure (variable) */ + u_int8_t ipt_ptr; /* index of current entry */ +#ifdef WORDS_BIGENDIAN + u_char ipt_oflw:4, /* overflow counter */ + ipt_flg:4; /* flags, see below */ +#else + u_char ipt_flg:4, /* flags, see below */ + ipt_oflw:4; /* overflow counter */ +#endif + union ipt_timestamp { + n_long ipt_time[1]; + struct ipt_ta { + struct in_addr ipt_addr; + n_long ipt_time; + } ipt_ta[1]; + } ipt_timestamp; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +/* flag bits for ipt_flg */ +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ + +/* bits for security (not byte swapped) */ +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 + +/* + * Internet implementation parameters. + */ +#define MAXTTL 255 /* maximum time to live (seconds) */ +#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ +#define IPFRAGTTL 60 /* time to live for frags, slowhz */ +#define IPTTLDEC 1 /* subtracted when forwarding */ + +#define IP_MSS 576 /* default maximum segment size */ + +#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ +#include +#else +#if SIZEOF_CHAR_P == 4 +typedef SLIRPcaddr_t caddr32_t; +#else +typedef u_int32_t caddr32_t; +#endif +#endif + +#if SIZEOF_CHAR_P == 4 +typedef struct ipq *ipqp_32; +typedef struct ipasfrag *ipasfragp_32; +#else +typedef caddr32_t ipqp_32; +typedef caddr32_t ipasfragp_32; +#endif + +/* + * Overlay for ip header used by other protocols (tcp, udp). + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ipovly { + caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ + u_int8_t ih_x1; /* (unused) */ + u_int8_t ih_pr; /* protocol */ + u_int16_t ih_len; /* protocol length */ + struct in_addr ih_src; /* source internet address */ + struct in_addr ih_dst; /* destination internet address */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +#if defined(_MSC_VER) +#pragma pack(pop) +#endif + +/* + * Ip reassembly queue structure. Each fragment + * being reassembled is attached to one of these structures. + * They are timed out after ipq_ttl drops to 0, and may also + * be reclaimed if memory becomes tight. + * size 28 bytes + */ +struct ipq { + ipqp_32 next,prev; /* to other reass headers */ + u_int8_t ipq_ttl; /* time for reass q to live */ + u_int8_t ipq_p; /* protocol of this fragment */ + u_int16_t ipq_id; /* sequence id for reassembly */ + ipasfragp_32 ipq_next,ipq_prev; + /* to ip headers of fragments */ + struct in_addr ipq_src,ipq_dst; +}; + +/* + * Ip header, when holding a fragment. + * + * Note: ipf_next must be at same offset as ipq_next above + */ +struct ipasfrag { +#ifdef WORDS_BIGENDIAN + u_char ip_v:4, + ip_hl:4; +#else + u_char ip_hl:4, + ip_v:4; +#endif + /* BUG : u_int changed to u_int8_t. + * sizeof(u_int)==4 on linux 2.0 + */ + u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit + * to avoid destroying tos (PPPDTRuu); + * copied from (ip_off&IP_MF) */ + u_int16_t ip_len; + u_int16_t ip_id; + u_int16_t ip_off; + u_int8_t ip_ttl; + u_int8_t ip_p; + u_int16_t ip_sum; + ipasfragp_32 ipf_next; /* next fragment */ + ipasfragp_32 ipf_prev; /* previous fragment */ +}; + +/* + * Structure stored in mbuf in inpcb.ip_options + * and passed to ip_output when ip options are in use. + * The actual length of the options (including ipopt_dst) + * is in m_len. + */ +#define MAX_IPOPTLEN 40 + +struct ipoption { + struct in_addr ipopt_dst; /* first-hop dst if source routed */ + int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ +}; + +/* + * Structure attached to inpcb.ip_moptions and + * passed to ip_output when IP multicast options are in use. + */ + +struct ipstat { + u_long ips_total; /* total packets received */ + u_long ips_badsum; /* checksum bad */ + u_long ips_tooshort; /* packet too short */ + u_long ips_toosmall; /* not enough data */ + u_long ips_badhlen; /* ip header length < data size */ + u_long ips_badlen; /* ip length < ip header length */ + u_long ips_fragments; /* fragments received */ + u_long ips_fragdropped; /* frags dropped (dups, out of space) */ + u_long ips_fragtimeout; /* fragments timed out */ + u_long ips_forward; /* packets forwarded */ + u_long ips_cantforward; /* packets rcvd for unreachable dest */ + u_long ips_redirectsent; /* packets forwarded on same net */ + u_long ips_noproto; /* unknown or unsupported protocol */ + u_long ips_delivered; /* datagrams delivered to upper level*/ + u_long ips_localout; /* total ip packets generated here */ + u_long ips_odropped; /* lost packets due to nobufs, etc. */ + u_long ips_reassembled; /* total packets reassembled ok */ + u_long ips_fragmented; /* datagrams successfully fragmented */ + u_long ips_ofragments; /* output fragments created */ + u_long ips_cantfrag; /* don't fragment flag was set, etc. */ + u_long ips_badoptions; /* error in option processing */ + u_long ips_noroute; /* packets discarded due to no route */ + u_long ips_badvers; /* ip version != 4 */ + u_long ips_rawout; /* total raw ip packets generated */ + u_long ips_unaligned; /* times the ip packet was not aligned */ +}; + +extern struct ipstat ipstat; +extern struct ipq ipq; /* ip reass. queue */ +extern u_int16_t ip_id; /* ip packet ctr, for ids */ +extern int ip_defttl; /* default IP ttl */ + +#endif diff --git a/src/slirp/ip_icmp.c b/src/slirp/ip_icmp.c new file mode 100644 index 000000000..3106147bd --- /dev/null +++ b/src/slirp/ip_icmp.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 + * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp + */ + +#include "slirp.h" +#include "ip_icmp.h" + +struct icmpstat icmpstat; + +/* The message sent when emulating PING */ +/* Be nice and tell them it's just a psuedo-ping packet */ +char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; + +/* list of actions for icmp_error() on RX of an icmp message */ +static int icmp_flush[19] = { +/* ECHO REPLY (0) */ 0, + 1, + 1, +/* DEST UNREACH (3) */ 1, +/* SOURCE QUENCH (4)*/ 1, +/* REDIRECT (5) */ 1, + 1, + 1, +/* ECHO (8) */ 0, +/* ROUTERADVERT (9) */ 1, +/* ROUTERSOLICIT (10) */ 1, +/* TIME EXCEEDED (11) */ 1, +/* PARAMETER PROBLEM (12) */ 1, +/* TIMESTAMP (13) */ 0, +/* TIMESTAMP REPLY (14) */ 0, +/* INFO (15) */ 0, +/* INFO REPLY (16) */ 0, +/* ADDR MASK (17) */ 0, +/* ADDR MASK REPLY (18) */ 0 +}; + +/* + * Process a received ICMP message. + */ +void +icmp_input(m, hlen) + struct SLIRPmbuf *m; + int hlen; +{ + register struct icmp *icp; + register struct ip *ip=mtod(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 SLIRPmbuf, and check + * that its not corrupted and of at least minimum length. + */ + if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ + icmpstat.icps_tooshort++; + freeit: + m_freem(m); + goto end_error; + } + + m->m_len -= hlen; + m->m_data += hlen; + icp = mtod(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; */ + + DEBUG_ARG("icmp_type = %d", icp->icmp_type); + switch (icp->icmp_type) { + case ICMP_ECHO: + icp->icmp_type = ICMP_ECHOREPLY; + ip->ip_len += hlen; /* since ip_input subtracts this */ + if (ip->ip_dst.s_addr == alias_addr.s_addr) { + icmp_reflect(m); + } else { + struct SLIRPsocket *so; + 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", + errno,strerror(errno))); + sofree(so); + m_free(m); + goto end_error; + } + so->so_m = m; + so->so_faddr = ip->ip_dst; + so->so_fport = htons(7); + so->so_laddr = ip->ip_src; + so->so_lport = htons(9); + 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; + } + } else { + addr.sin_addr = so->so_faddr; + } + addr.sin_port = so->so_fport; + if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, + (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)); + udp_detach(so); + } + } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ + break; + case ICMP_UNREACH: + /* XXX? report error? close socket? */ + case ICMP_TIMXCEED: + case ICMP_PARAMPROB: + case ICMP_SOURCEQUENCH: + case ICMP_TSTAMP: + case ICMP_MASKREQ: + case ICMP_REDIRECT: + icmpstat.icps_notsupp++; + m_freem(m); + break; + + default: + icmpstat.icps_badtype++; + m_freem(m); + } /* swith */ + +end_error: + /* m is m_free()'d xor put in a socket xor or given to ip_send */ + return; +} + + +/* + * Send an ICMP message in response to a situation + * + * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). + * MUST NOT change this header information. + * MUST NOT reply to a multicast/broadcast IP address. + * MUST NOT reply to a multicast/broadcast MAC address. + * MUST reply to only the first fragment. + */ +/* + * Send ICMP_UNREACH back to the source regarding msrc. + * SLIRPmbuf *msrc is used as a template, but is NOT m_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 + * 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 SLIRPmbuf *msrc; + u_char type; + u_char code; + int minsize; + char *message; +{ + unsigned hlen, shlen, s_ip_len; + register struct ip *ip; + register struct icmp *icp; + register struct SLIRPmbuf *m; + + DEBUG_CALL("icmp_error"); + DEBUG_ARG("msrc = %lx", (long )msrc); + DEBUG_ARG("msrc_len = %d", msrc->m_len); + + if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; + + /* check msrc */ + if(!msrc) goto end_error; + ip = mtod(msrc, struct ip *); +#if SLIRP_DEBUG + { char bufa[20], bufb[20]; + strcpy(bufa, inet_ntoa(ip->ip_src)); + strcpy(bufb, inet_ntoa(ip->ip_dst)); + DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); + } +#endif + if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ + + shlen=ip->ip_hl << 2; + s_ip_len=ip->ip_len; + if(ip->ip_p == IPPROTO_ICMP) { + icp = (struct icmp *)((char *)ip + shlen); + /* + * Assume any unknown ICMP type is an error. This isn't + * specified by the RFC, but think about it.. + */ + if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; + } + + /* make a copy */ + if(!(m=m_get())) goto end_error; /* get SLIRPmbuf */ + { u_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); + } + 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 *); + hlen= sizeof(struct ip ); /* no options in reply */ + + /* fill in icmp */ + m->m_data += hlen; + m->m_len -= hlen; + + icp = mtod(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 */ + + /* min. size = 8+sizeof(struct ip)+8 */ + + icp->icmp_type = type; + icp->icmp_code = code; + icp->icmp_id = 0; + icp->icmp_seq = 0; + + memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ + HTONS(icp->icmp_ip.ip_len); + HTONS(icp->icmp_ip.ip_id); + HTONS(icp->icmp_ip.ip_off); + +#if SLIRP_DEBUG + if(message) { /* DEBUG : append message to ICMP packet */ + int message_len; + char *cpnt; + message_len=strlen(message); + if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; + cpnt=(char *)m->m_data+m->m_len; + memcpy(cpnt, message, message_len); + m->m_len+=message_len; + } +#endif + + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, m->m_len); + + m->m_data -= hlen; + m->m_len += hlen; + + /* fill in ip */ + ip->ip_hl = hlen >> 2; + ip->ip_len = (u_int16_t)m->m_len; + + ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ + + ip->ip_ttl = MAXTTL; + ip->ip_p = IPPROTO_ICMP; + ip->ip_dst = ip->ip_src; /* ip adresses */ + ip->ip_src = alias_addr; + + (void ) ip_output((struct SLIRPsocket *)NULL, m); + + icmpstat.icps_reflect++; + +end_error: + return; +} +#undef ICMP_MAXDATALEN + +/* + * Reflect the ip packet back to the source + */ +void +icmp_reflect(m) + struct SLIRPmbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + int hlen = ip->ip_hl << 2; + int optlen = hlen - sizeof(struct ip ); + register struct icmp *icp; + + /* + * Send an icmp packet back to the ip level, + * after supplying a checksum. + */ + m->m_data += hlen; + m->m_len -= hlen; + icp = mtod(m, struct icmp *); + + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, ip->ip_len - hlen); + + m->m_data -= hlen; + m->m_len += hlen; + + /* fill in ip */ + if (optlen > 0) { + /* + * Strip out original options by copying rest of first + * SLIRPmbuf's data back, and adjust the IP length. + */ + memmove((SLIRPcaddr_t)(ip + 1), (SLIRPcaddr_t)ip + hlen, + (unsigned )(m->m_len - hlen)); + hlen -= optlen; + ip->ip_hl = hlen >> 2; + ip->ip_len -= optlen; + m->m_len -= optlen; + } + + ip->ip_ttl = MAXTTL; + { /* swap */ + struct in_addr icmp_dst; + icmp_dst = ip->ip_dst; + ip->ip_dst = ip->ip_src; + ip->ip_src = icmp_dst; + } + + (void ) ip_output((struct SLIRPsocket *)NULL, m); + + icmpstat.icps_reflect++; +} diff --git a/src/slirp/ip_icmp.h b/src/slirp/ip_icmp.h new file mode 100644 index 000000000..20fcda1bd --- /dev/null +++ b/src/slirp/ip_icmp.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 + * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp + */ + +#ifndef _NETINET_IP_ICMP_H_ +#define _NETINET_IP_ICMP_H_ + +/* + * Interface Control Message Protocol Definitions. + * Per RFC 792, September 1981. + */ + +typedef u_int32_t n_time; + +/* + * Structure of an icmp header. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct icmp { + u_char icmp_type; /* type of message, see below */ + u_char icmp_code; /* type sub code */ + u_short icmp_cksum; /* ones complement cksum of struct */ + union { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ + struct ih_idseq { + u_short icd_id; + u_short icd_seq; + } ih_idseq; + int ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu { + u_short ipm_void; + u_short ipm_nextmtu; + } ih_pmtu; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu + union { + struct id_ts { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + } id_ts; + struct id_ip { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + uint32_t id_mask; + char id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(0) +#endif + +/* + * Lower bounds on packet lengths for various types. + * For the error advice packets must first insure that the + * packet is large enought to contain the returned ip header. + * Only then can we do the check to see if 64 bits of packet + * data have been returned, since we need to check the returned + * ip header length. + */ +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ +#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + /* N.B.: must separately check that ip_hl >= 5 */ + +/* + * Definition of type and code field values. + */ +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_ROUTERADVERT 9 /* router advertisement */ +#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_IREQ 15 /* information request */ +#define ICMP_IREQREPLY 16 /* information reply */ +#define ICMP_MASKREQ 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ + +#define ICMP_MAXTYPE 18 + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ + (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) + +void icmp_input _P((struct SLIRPmbuf *, int)); +void icmp_error _P((struct SLIRPmbuf *, u_char, u_char, int, char *)); +void icmp_reflect _P((struct SLIRPmbuf *)); + +#endif diff --git a/src/slirp/ip_input.c b/src/slirp/ip_input.c new file mode 100644 index 000000000..fb8f3fcf1 --- /dev/null +++ b/src/slirp/ip_input.c @@ -0,0 +1,693 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 + * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp + */ + +/* + * Changes and additions relating to SLiRP are + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" +#include "ip_icmp.h" + +int ip_defttl; +struct ipstat ipstat; +struct ipq ipq; + +/* + * IP initialization: fill in IP protocol switch table. + * All protocols not implemented in kernel go to raw IP protocol handler. + */ +void +ip_init() +{ + ipq.next = ipq.prev = (ipqp_32)&ipq; + ip_id = tt.tv_sec & 0xffff; + udp_init(); + tcp_init(); + ip_defttl = IPDEFTTL; +} + +/* + * Ip input routine. Checksum and byte swap header. If fragmented + * try to reassemble. Process options. Pass to next level. + */ +void +ip_input(m) + struct SLIRPmbuf *m; +{ + register struct ip *ip; + u_int hlen; + + DEBUG_CALL("ip_input"); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("m_len = %d", m->m_len); + + ipstat.ips_total++; + + if (m->m_len < sizeof (struct ip)) { + ipstat.ips_toosmall++; + return; + } + + ip = mtod(m, struct ip *); + + if (ip->ip_v != IPVERSION) { + ipstat.ips_badvers++; + goto bad; + } + + hlen = ip->ip_hl << 2; + if (hlenm->m_len) {/* min header length */ + ipstat.ips_badhlen++; /* or packet too short */ + goto bad; + } + + /* keep ip header intact for ICMP reply + * ip->ip_sum = cksum(m, hlen); + * if (ip->ip_sum) { + */ + if(cksum(m,hlen)) { + ipstat.ips_badsum++; + goto bad; + } + + /* + * Convert fields to host representation. + */ + NTOHS(ip->ip_len); + if (ip->ip_len < hlen) { + ipstat.ips_badlen++; + goto bad; + } + NTOHS(ip->ip_id); + NTOHS(ip->ip_off); + + /* + * Check that the amount of data in the buffers + * is as at least much as the IP header would have us expect. + * Trim SLIRPmbufs if longer than we expect. + * Drop packet if shorter than we expect. + */ + if (m->m_len < ip->ip_len) { + ipstat.ips_tooshort++; + goto bad; + } + /* Should drop packet if SLIRPmbuf too long? hmmm... */ + if (m->m_len > ip->ip_len) + m_adj(m, ip->ip_len - m->m_len); + + /* check ip_ttl for a correct ICMP reply */ + if(ip->ip_ttl==0 || ip->ip_ttl==1) { + icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); + goto bad; + } + + /* + * Process options and, if not destined for us, + * ship it on. ip_dooptions returns 1 when an + * error was detected (causing an icmp message + * to be sent and the original packet to be freed). + */ +/* We do no IP options */ +/* if (hlen > sizeof (struct ip) && ip_dooptions(m)) + * goto next; + */ + /* + * If offset or IP_MF are set, must reassemble. + * Otherwise, nothing need be done. + * (We could look in the reassembly queue to see + * if the packet was previously fragmented, + * but it's not worth the time; just let them time out.) + * + * XXX This should fail, don't fragment yet + */ + if (ip->ip_off &~ IP_DF) { + register struct ipq *fp; + /* + * Look for queue of fragments + * of this datagram. + */ + for (fp = (struct ipq *) ipq.next; fp != &ipq; + fp = (struct ipq *) fp->next) + if (ip->ip_id == fp->ipq_id && + ip->ip_src.s_addr == fp->ipq_src.s_addr && + ip->ip_dst.s_addr == fp->ipq_dst.s_addr && + ip->ip_p == fp->ipq_p) + goto found; + fp = 0; + found: + + /* + * Adjust ip_len to not reflect header, + * set ip_mff if more fragments are expected, + * convert offset of this to bytes. + */ + ip->ip_len -= hlen; + if (ip->ip_off & IP_MF) + ((struct ipasfrag *)ip)->ipf_mff |= 1; + else + ((struct ipasfrag *)ip)->ipf_mff &= ~1; + + ip->ip_off <<= 3; + + /* + * If datagram marked as having more fragments + * or if this is not the first fragment, + * attempt reassembly; if it succeeds, proceed. + */ + if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { + ipstat.ips_fragments++; + ip = ip_reass((struct ipasfrag *)ip, fp); + if (ip == 0) + return; + ipstat.ips_reassembled++; + m = dtom(ip); + } else + if (fp) + ip_freef(fp); + + } else + ip->ip_len -= hlen; + + /* + * Switch out to protocol's input routine. + */ + ipstat.ips_delivered++; + switch (ip->ip_p) { + case IPPROTO_TCP: + tcp_input(m, hlen, (struct SLIRPsocket *)NULL); + break; + case IPPROTO_UDP: + udp_input(m, hlen); + break; + case IPPROTO_ICMP: + icmp_input(m, hlen); + break; + default: + ipstat.ips_noproto++; + m_free(m); + } + return; +bad: + m_freem(m); + return; +} + +/* + * Take incoming datagram fragment and try to + * reassemble it into whole datagram. If a chain for + * reassembly of this datagram already exists, then it + * is given as fp; otherwise have to make a chain. + */ +struct ip * +ip_reass(ip, fp) + register struct ipasfrag *ip; + register struct ipq *fp; +{ + register struct SLIRPmbuf *m = dtom(ip); + register struct ipasfrag *q; + int hlen = ip->ip_hl << 2; + int i, next; + + DEBUG_CALL("ip_reass"); + DEBUG_ARG("ip = %lx", (long)ip); + DEBUG_ARG("fp = %lx", (long)fp); + DEBUG_ARG("m = %lx", (long)m); + + /* + * Presence of header sizes in SLIRPmbufs + * would confuse code below. + * Fragment m_data is concatenated. + */ + m->m_data += hlen; + m->m_len -= hlen; + + /* + * If first fragment to arrive, create a reassembly queue. + */ + if (fp == 0) { + struct SLIRPmbuf *t; + if ((t = m_get()) == NULL) goto dropfrag; + fp = mtod(t, struct ipq *); + insque_32(fp, &ipq); + fp->ipq_ttl = IPFRAGTTL; + fp->ipq_p = ip->ip_p; + fp->ipq_id = ip->ip_id; + fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; + fp->ipq_src = ((struct ip *)ip)->ip_src; + fp->ipq_dst = ((struct ip *)ip)->ip_dst; + q = (struct ipasfrag *)fp; + goto insert; + } + + /* + * Find a segment which begins after this one does. + */ + for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; + q = (struct ipasfrag *)q->ipf_next) + if (q->ip_off > ip->ip_off) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if (q->ipf_prev != (ipasfragp_32)fp) { + i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + + ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; + if (i > 0) { + if (i >= ip->ip_len) + goto dropfrag; + m_adj(dtom(ip), i); + ip->ip_off += i; + ip->ip_len -= i; + } + } + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { + i = (ip->ip_off + ip->ip_len) - q->ip_off; + if (i < q->ip_len) { + q->ip_len -= i; + q->ip_off += i; + m_adj(dtom(q), i); + break; + } + q = (struct ipasfrag *) q->ipf_next; + m_freem(dtom((struct ipasfrag *) q->ipf_prev)); + ip_deq((struct ipasfrag *) q->ipf_prev); + } + +insert: + /* + * Stick new segment in its place; + * check for complete reassembly. + */ + ip_enq(ip, (struct ipasfrag *) q->ipf_prev); + next = 0; + for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; + q = (struct ipasfrag *) q->ipf_next) { + if (q->ip_off != next) + return (0); + next += q->ip_len; + } + if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) + return (0); + + /* + * Reassembly is complete; concatenate fragments. + */ + q = (struct ipasfrag *) fp->ipq_next; + m = dtom(q); + + q = (struct ipasfrag *) q->ipf_next; + while (q != (struct ipasfrag *)fp) { + struct SLIRPmbuf *t; + t = dtom(q); + q = (struct ipasfrag *) q->ipf_next; + m_cat(m, t); + } + + /* + * Create header for new ip packet by + * modifying header of first packet; + * dequeue and discard fragment reassembly header. + * Make header visible. + */ + ip = (struct ipasfrag *) fp->ipq_next; + + /* + * If the fragments concatenated to an SLIRPmbuf that's + * bigger than the total size of the fragment, then and + * m_ext buffer was alloced. But fp->ipq_next points to + * the old buffer (in the SLIRPmbuf), so we must point ip + * into the new buffer. + */ + if (m->m_flags & M_EXT) { + int delta; + delta = (char *)ip - m->m_dat; + ip = (struct ipasfrag *)(m->m_ext + delta); + } + + /* DEBUG_ARG("ip = %lx", (long)ip); + * ip=(struct ipasfrag *)m->m_data; */ + + ip->ip_len = next; + ip->ipf_mff &= ~1; + ((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); + m->m_len += (ip->ip_hl << 2); + m->m_data -= (ip->ip_hl << 2); + + return ((struct ip *)ip); + +dropfrag: + ipstat.ips_fragdropped++; + m_freem(m); + return (0); +} + +/* + * Free a fragment reassembly header and all + * associated datagrams. + */ +void +ip_freef(fp) + struct ipq *fp; +{ + register struct ipasfrag *q, *p; + + for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; + q = p) { + p = (struct ipasfrag *) q->ipf_next; + ip_deq(q); + m_freem(dtom(q)); + } + remque_32(fp); + (void) m_free(dtom(fp)); +} + +/* + * Put an ip fragment on a reassembly chain. + * Like insque, but pointers in middle of structure. + */ +void +ip_enq(p, prev) + register struct ipasfrag *p, *prev; +{ + DEBUG_CALL("ip_enq"); + DEBUG_ARG("prev = %lx", (long)prev); + p->ipf_prev = (ipasfragp_32) prev; + p->ipf_next = prev->ipf_next; + ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p; + prev->ipf_next = (ipasfragp_32) p; +} + +/* + * To ip_enq as remque is to insque. + */ +void +ip_deq(p) + register struct ipasfrag *p; +{ + ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; + ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; +} + +/* + * IP timer processing; + * if a timer expires on a reassembly + * queue, discard it. + */ +void +ip_slowtimo() +{ + register struct ipq *fp; + + DEBUG_CALL("ip_slowtimo"); + + fp = (struct ipq *) ipq.next; + if (fp == 0) + return; + + while (fp != &ipq) { + --fp->ipq_ttl; + fp = (struct ipq *) fp->next; + if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { + ipstat.ips_fragtimeout++; + ip_freef((struct ipq *) fp->prev); + } + } +} + +/* + * Do option processing on a datagram, + * possibly discarding it if bad options are encountered, + * or forwarding it if source-routed. + * Returns 1 if packet has been forwarded/freed, + * 0 if the packet should be processed further. + */ + +#ifdef notdef + +int +ip_dooptions(m) + struct SLIRPmbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + register u_char *cp; + register struct ip_timestamp *ipt; + register struct in_ifaddr *ia; +/* int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */ + int opt, optlen, cnt, off, code, type, forward = 0; + struct in_addr *sin, dst; +typedef u_int32_t n_time; + n_time ntime; + + dst = ip->ip_dst; + cp = (u_char *)(ip + 1); + cnt = (ip->ip_hl << 2) - sizeof (struct ip); + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + optlen = 1; + else { + optlen = cp[IPOPT_OLEN]; + if (optlen <= 0 || optlen > cnt) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + } + switch (opt) { + + default: + break; + + /* + * Source routing with record. + * Find interface with current destination address. + * If none on this machine then drop if strictly routed, + * or do nothing if loosely routed. + * Record interface address and bring up next address + * component. If strictly routed make sure next + * address is on directly accessible net. + */ + case IPOPT_LSRR: + case IPOPT_SSRR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + ipaddr.sin_addr = ip->ip_dst; + ia = (struct in_ifaddr *) + ifa_ifwithaddr((struct sockaddr *)&ipaddr); + if (ia == 0) { + if (opt == IPOPT_SSRR) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + /* + * Loose routing, and not at next destination + * yet; nothing to do except forward. + */ + break; + } + off--; / * 0 origin * / + if (off > optlen - sizeof(struct in_addr)) { + /* + * End of source route. Should be for us. + */ + save_rte(cp, ip->ip_src); + break; + } + /* + * locate outgoing interface + */ + bcopy((SLIRPcaddr_t)(cp + off), (SLIRPcaddr_t)&ipaddr.sin_addr, + sizeof(ipaddr.sin_addr)); + if (opt == IPOPT_SSRR) { +#define INA struct in_ifaddr * +#define SA struct sockaddr * + if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) + ia = (INA)ifa_ifwithnet((SA)&ipaddr); + } else + ia = ip_rtaddr(ipaddr.sin_addr); + if (ia == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + ip->ip_dst = ipaddr.sin_addr; + bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr), + (SLIRPcaddr_t)(cp + off), sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + /* + * Let ip_intr's mcast routing check handle mcast pkts + */ + forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); + break; + + case IPOPT_RR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + /* + * If no space remains, ignore. + */ + off--; * 0 origin * + if (off > optlen - sizeof(struct in_addr)) + break; + bcopy((SLIRPcaddr_t)(&ip->ip_dst), (SLIRPcaddr_t)&ipaddr.sin_addr, + sizeof(ipaddr.sin_addr)); + /* + * locate outgoing interface; if we're the destination, + * use the incoming interface (should be same). + */ + if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && + (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_HOST; + goto bad; + } + bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr), + (SLIRPcaddr_t)(cp + off), sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + break; + + case IPOPT_TS: + code = cp - (u_char *)ip; + ipt = (struct ip_timestamp *)cp; + if (ipt->ipt_len < 5) + goto bad; + if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) { + if (++ipt->ipt_oflw == 0) + goto bad; + break; + } + sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); + switch (ipt->ipt_flg) { + + case IPOPT_TS_TSONLY: + break; + + case IPOPT_TS_TSANDADDR: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + ipaddr.sin_addr = dst; + ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr, + m->m_pkthdr.rcvif); + if (ia == 0) + continue; + bcopy((SLIRPcaddr_t)&IA_SIN(ia)->sin_addr, + (SLIRPcaddr_t)sin, sizeof(struct in_addr)); + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + case IPOPT_TS_PRESPEC: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + bcopy((SLIRPcaddr_t)sin, (SLIRPcaddr_t)&ipaddr.sin_addr, + sizeof(struct in_addr)); + if (ifa_ifwithaddr((SA)&ipaddr) == 0) + continue; + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + default: + goto bad; + } + ntime = iptime(); + bcopy((SLIRPcaddr_t)&ntime, (SLIRPcaddr_t)cp + ipt->ipt_ptr - 1, + sizeof(n_time)); + ipt->ipt_ptr += sizeof(n_time); + } + } + if (forward) { + ip_forward(m, 1); + return (1); + } + } + } + return (0); +bad: + /* ip->ip_len -= ip->ip_hl << 2; XXX icmp_error adds in hdr length */ + +/* Not yet */ + icmp_error(m, type, code, 0, 0); + + ipstat.ips_badoptions++; + return (1); +} + +#endif /* notdef */ + +/* + * Strip out IP options, at higher + * level protocol in the kernel. + * Second argument is buffer to which options + * will be moved, and return value is their length. + * (XXX) should be deleted; last arg currently ignored. + */ +void +ip_stripoptions(m, mopt) + struct SLIRPmbuf *m; + struct SLIRPmbuf *mopt; +{ + register int i; + struct ip *ip = mtod(m, struct ip *); + register SLIRPcaddr_t opts; + int olen; + + olen = (ip->ip_hl<<2) - sizeof (struct ip); + opts = (SLIRPcaddr_t)(ip + 1); + i = m->m_len - (sizeof (struct ip) + olen); + memcpy(opts, opts + olen, (unsigned)i); + m->m_len -= olen; + + ip->ip_hl = sizeof(struct ip) >> 2; +} diff --git a/src/slirp/ip_output.c b/src/slirp/ip_output.c new file mode 100644 index 000000000..c3f243e76 --- /dev/null +++ b/src/slirp/ip_output.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 + * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp + */ + +/* + * Changes and additions relating to SLiRP are + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +u_int16_t ip_id; + +/* + * IP output. The packet in SLIRPmbuf chain m contains a skeletal IP + * header (with len, off, ttl, proto, tos, src, dst). + * The SLIRPmbuf chain containing the packet will be freed. + * The SLIRPmbuf opt, if present, will not be freed. + */ +int +ip_output(so, m0) + struct SLIRPsocket *so; + struct SLIRPmbuf *m0; +{ + struct ip *ip; + struct SLIRPmbuf *m = m0; + u_int hlen = sizeof(struct ip ); + u_int len, off; + int error = 0; + + DEBUG_CALL("ip_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m0 = %lx", (long)m0); + + /* We do no options */ +/* if (opt) { + * m = ip_insertoptions(m, opt, &len); + * hlen = len; + * } + */ + ip = mtod(m, struct ip *); + /* + * Fill in IP header. + */ + ip->ip_v = IPVERSION; + ip->ip_off &= IP_DF; + ip->ip_id = htons(ip_id++); + ip->ip_hl = hlen >> 2; + ipstat.ips_localout++; + + /* + * Verify that we have any chance at all of being able to queue + * the packet or packet fragments + */ + /* XXX Hmmm... */ +/* if (if_queued > if_thresh && towrite <= 0) { + * error = ENOBUFS; + * goto bad; + * } + */ + + /* + * If small enough for interface, can just send directly. + */ + if ((u_int16_t)ip->ip_len <= if_mtu) { + ip->ip_len = htons((u_int16_t)ip->ip_len); + ip->ip_off = htons((u_int16_t)ip->ip_off); + ip->ip_sum = 0; + ip->ip_sum = cksum(m, hlen); + + if_output(so, m); + goto done; + } + + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + if (ip->ip_off & IP_DF) { + error = -1; + ipstat.ips_cantfrag++; + goto bad; + } + + len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ + if (len < 8) { + error = -1; + goto bad; + } + + { + int mhlen, firstlen = len; + struct SLIRPmbuf **mnext = &m->m_nextpkt; + + /* + * Loop through length of segment after first fragment, + * make new header and copy data of each part and link onto chain. + */ + m0 = m; + mhlen = sizeof (struct ip); + for (off = hlen + len; off < ip->ip_len; off += len) { + struct ip *mhip; + m = m_get(); + if (m == 0) { + error = -1; + ipstat.ips_odropped++; + goto sendorfree; + } + m->m_data += if_maxlinkhdr; + mhip = mtod(m, struct ip *); + *mhip = *ip; + + /* No options */ +/* if (hlen > sizeof (struct ip)) { + * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); + * mhip->ip_hl = mhlen >> 2; + * } + */ + m->m_len = mhlen; + mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); + if (ip->ip_off & IP_MF) + mhip->ip_off |= IP_MF; + if (off + len >= (u_int16_t)ip->ip_len) + len = (u_int16_t)ip->ip_len - off; + else + mhip->ip_off |= IP_MF; + mhip->ip_len = htons((u_int16_t)(len + mhlen)); + + if (m_copy(m, m0, off, len) < 0) { + error = -1; + goto sendorfree; + } + + mhip->ip_off = htons((u_int16_t)mhip->ip_off); + mhip->ip_sum = 0; + mhip->ip_sum = cksum(m, mhlen); + *mnext = m; + mnext = &m->m_nextpkt; + ipstat.ips_ofragments++; + } + /* + * Update first fragment by trimming what's been copied out + * and updating header, then send each fragment (in order). + */ + m = m0; + m_adj(m, hlen + firstlen - 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; + ip->ip_sum = cksum(m, hlen); +sendorfree: + for (m = m0; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = 0; + if (error == 0) + if_output(so, m); + else + m_freem(m); + } + + if (error == 0) + ipstat.ips_fragmented++; + } + +done: + return (error); + +bad: + m_freem(m0); + goto done; +} diff --git a/src/slirp/libslirp.h b/src/slirp/libslirp.h new file mode 100644 index 000000000..8a1aa31e6 --- /dev/null +++ b/src/slirp/libslirp.h @@ -0,0 +1,41 @@ +#ifndef _LIBSLIRP_H +#define _LIBSLIRP_H + +#ifdef _WIN32 +#include +int inet_aton(const char *cp, struct in_addr *ia); +#else +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int slirp_init(void); + +int 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); + +void slirp_input(const uint8 *pkt, int pkt_len); + +/* you must provide the following functions: */ +int slirp_can_output(void); +void slirp_output(const uint8 *pkt, int pkt_len); + +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); + +extern const char *tftp_prefix; +extern char slirp_hostname[33]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/slirp/main.h b/src/slirp/main.h new file mode 100644 index 000000000..181b6ae88 --- /dev/null +++ b/src/slirp/main.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#define TOWRITEMAX 512 + +extern struct timeval tt; +extern int link_up; +extern int slirp_socket; +extern int slirp_socket_unit; +extern int slirp_socket_port; +extern u_int32_t slirp_socket_addr; +extern char *slirp_socket_passwd; +extern int ctty_closed; + +/* + * Get the difference in 2 times from updtim() + * Allow for wraparound times, "just in case" + * x is the greater of the 2 (current time) and y is + * what it's being compared against. + */ +#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y) + +extern char *slirp_tty; +extern char *exec_shell; +extern u_int curtime; +extern fd_set *global_readfds, *global_writefds, *global_xfds; +extern struct in_addr ctl_addr; +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 char *username; +extern char *socket_path; +extern int towrite_max; +extern int ppp_exit; +extern int so_options; +extern int tcp_keepintvl; +extern uint8_t client_ethaddr[6]; + +#define PROTO_SLIP 0x1 +#ifdef USE_PPP +#define PROTO_PPP 0x2 +#endif + +void if_encap(const uint8_t *ip_data, int ip_data_len); diff --git a/src/slirp/mbuf.c b/src/slirp/mbuf.c new file mode 100644 index 000000000..c7f3f3fe8 --- /dev/null +++ b/src/slirp/mbuf.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1995 Danny Gasparovski + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +/* + * mbuf's in SLiRP are much simpler than the real mbufs in + * FreeBSD. They are fixed size, determined by the MTU, + * so that one whole packet can fit. Mbuf's cannot be + * chained together. If there's more data than the mbuf + * could hold, an external malloced buffer is pointed to + * by m_ext (and the data pointers) and M_EXT is set in + * the flags + */ + +#include +#include "slirp.h" + +struct mbuf *mbutl; +char *mclrefcnt; +int mbuf_alloced = 0; +struct SLIRPmbuf m_freelist, m_usedlist; +int mbuf_thresh = 30; +int mbuf_max = 0; +size_t msize; + +void +m_init() +{ + m_freelist.m_next = m_freelist.m_prev = &m_freelist; + m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; + msize_init(); +} + +void msize_init() +{ + /* + * Find a nice value for msize + * XXX if_maxlinkhdr already in mtu + */ + msize = (if_mtu>if_mru?if_mtu:if_mru) + + if_maxlinkhdr + sizeof(struct m_hdr ) + 6; +} + +/* + * Get an mbuf from the free list, if there are none + * malloc one + * + * Because fragmentation can occur if we alloc new mbufs and + * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, + * which tells m_free to actually free() it + */ +struct SLIRPmbuf * m_get() +{ + struct SLIRPmbuf *m; + int flags = 0; + + DEBUG_CALL("m_get"); + + if (m_freelist.m_next == &m_freelist) { + m = (struct SLIRPmbuf *)malloc(msize); + if (m == NULL) goto end_error; + mbuf_alloced++; + if (mbuf_alloced > mbuf_thresh) + flags = M_DOFREE; + if (mbuf_alloced > mbuf_max) + mbuf_max = mbuf_alloced; + } else { + m = m_freelist.m_next; + remque(m); + } + + /* Insert it in the used list */ + 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; +end_error: + DEBUG_ARG("m = %lx", (long )m); + return m; +} + +//For some reason this fails in GDB saying tehre is no m_flags member +void +m_free(m) + struct SLIRPmbuf *m; +{ + + DEBUG_CALL("m_free"); + DEBUG_ARG("m = %lx", (long )m); + + if(m) { + /* Remove from m_usedlist */ + if (m->m_flags & M_USEDLIST) + remque(m); + + + + /* If it's M_EXT, free() it */ + if (m->m_flags & M_EXT) + free(m->m_ext); + + /* + * Either free() it or put it on the free list + */ + if (m->m_flags & M_DOFREE) { + free(m); + mbuf_alloced--; + } else if ((m->m_flags & M_FREELIST) == 0) { + insque(m,&m_freelist); + m->m_flags = M_FREELIST; /* Clobber other flags */ + } + } /* if(m) */ +} + +/* + * Copy data from one mbuf to the end of + * the other.. if result is too big for one mbuf, malloc() + * an M_EXT data segment + */ +void +m_cat(m, n) + struct SLIRPmbuf *m, *n; +{ + /* + * If there's no room, realloc + */ + if (M_FREEROOM(m) < n->m_len) + m_inc(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); +} + + +/* make m size bytes large */ +void +m_inc(m, size) + struct SLIRPmbuf *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 SLIRPmbuf *)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 SLIRPmbuf *)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; + +} + + + +void +m_adj(m, len) + struct SLIRPmbuf *m; + int len; +{ + if (m == NULL) + return; + if (len >= 0) { + /* Trim from head */ + m->m_data += len; + m->m_len -= len; + } else { + /* Trim from tail */ + len = -len; + m->m_len -= len; + } +} + + +/* + * Copy len bytes from m, starting off bytes into n + */ +int +m_copy(n, m, off, len) + struct SLIRPmbuf *n, *m; + int off, len; +{ + if (len > M_FREEROOM(n)) + return -1; + + memcpy((n->m_data + n->m_len), (m->m_data + off), len); + n->m_len += len; + return 0; +} + + +/* + * 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 SLIRPmbuf * +dtom(dat) + void *dat; +{ + struct SLIRPmbuf *m; + + DEBUG_CALL("dtom"); + 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; + } else { + if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) + return m; + } + } + + DEBUG_ERROR((dfd, "dtom failed")); + + return (struct SLIRPmbuf *)0; +} + diff --git a/src/slirp/mbuf.h b/src/slirp/mbuf.h new file mode 100644 index 000000000..13ef81523 --- /dev/null +++ b/src/slirp/mbuf.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 + * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp + */ + +#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 SLIRPmbuf *)((int)(x) & ~(M_SIZE-1))) */ + +/* 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 + * 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 SLIRPmbuf *mh_next; /* Linked list of mbufs */ + struct SLIRPmbuf *mh_prev; + struct SLIRPmbuf *mh_nextpkt; /* Next packet in queue/record */ + struct SLIRPmbuf *mh_prevpkt; /* Flags aren't used in the output queue */ + int mh_flags; /* Misc flags */ + + size_t mh_size; /* Size of data */ + struct SLIRPsocket *mh_so; + + SLIRPcaddr_t mh_data; /* Location of data */ + size_t mh_len; /* Amount of data in this mbuf */ +}; + +/* + * 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) +#define M_TRAILINGSPACE M_FREEROOM + +struct SLIRPmbuf { + struct m_hdr m_hdr; + union M_dat { + char m_dat_[1]; /* ANSI don't like 0 sized arrays */ + char *m_ext_; + } M_dat; +}; + +#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_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 */ + +/* + * Mbuf statistics. XXX + */ + +struct mbstat { + int mbs_alloced; /* Number of mbufs allocated */ + +}; + +extern struct mbstat mbstat; +extern int mbuf_alloced; +extern struct SLIRPmbuf m_freelist, m_usedlist; +extern int mbuf_max; + +void m_init _P((void)); +void msize_init _P((void)); +struct SLIRPmbuf * m_get _P((void)); +void m_free _P((struct SLIRPmbuf *)); +void m_cat _P((register struct SLIRPmbuf *, register struct SLIRPmbuf *)); +void m_inc _P((struct SLIRPmbuf *, int)); +void m_adj _P((struct SLIRPmbuf *, int)); +int m_copy _P((struct SLIRPmbuf *, struct SLIRPmbuf *, int, int)); +struct SLIRPmbuf * dtom _P((void *)); + +#endif diff --git a/src/slirp/misc.c b/src/slirp/misc.c new file mode 100644 index 000000000..88c0c13e0 --- /dev/null +++ b/src/slirp/misc.c @@ -0,0 +1,970 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#include "slirp.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 SLIRPsocket *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 + +#ifndef HAVE_INET_ATON +int +inet_aton(cp, ia) + const char *cp; + struct in_addr *ia; +{ + u_int32_t addr = inet_addr(cp); + if (addr == 0xffffffff) + return 0; + ia->s_addr = addr; + return 1; +} +#endif + +/* + * Get our IP address and put it in our_addr + */ +void +getouraddr() +{ + char buff[512]; + struct hostent *he = NULL; +#define ANCIENT + #ifdef ANCIENT + if (gethostname(&buff,500) == 0) + he = gethostbyname(&buff); + if (he) + our_addr = *(struct in_addr *)he->h_addr; + if (our_addr.s_addr == 0) + our_addr.s_addr = loopback_addr.s_addr; + #else + if (gethostname(buff,256) == 0) + { + struct addrinfo hints = { 0 }; + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_INET; + struct addrinfo* ai; + if (getaddrinfo(buff, NULL, &hints, &ai) == 0) + { + our_addr = *(struct in_addr *)ai->ai_addr->sa_data; + freeaddrinfo(ai); + } + } + if (our_addr.s_addr == 0) + our_addr.s_addr = loopback_addr.s_addr; + #endif + #undef ANCIENT +} + +//#if SIZEOF_CHAR_P == 8 +//what?! + +struct quehead_32 { + u_int32_t qh_link; + u_int32_t qh_rlink; +}; + +inline void +insque_32(a, b) + void *a; + void *b; +{ + register struct quehead_32 *element = (struct quehead_32 *) a; + register struct quehead_32 *head = (struct quehead_32 *) b; + element->qh_link = head->qh_link; + head->qh_link = (u_int32_t)element; + element->qh_rlink = (u_int32_t)head; + ((struct quehead_32 *)(element->qh_link))->qh_rlink + = (u_int32_t)element; +} + +inline void +remque_32(a) + void *a; +{ + register struct quehead_32 *element = (struct quehead_32 *) a; + ((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink; + ((struct quehead_32 *)(element->qh_rlink))->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +//#endif /* SIZEOF_CHAR_P == 8 */ +//Should be for 64bit + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +void +insque(a, b) + void *a, *b; +{ + register struct quehead *element = (struct quehead *) a; + register struct quehead *head = (struct quehead *) b; + element->qh_link = head->qh_link; + head->qh_link = (struct quehead *)element; + element->qh_rlink = (struct quehead *)head; + ((struct quehead *)(element->qh_link))->qh_rlink + = (struct quehead *)element; +} + +void +remque(a) + void *a; +{ + register struct quehead *element = (struct quehead *) a; + ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; + ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; + element->qh_rlink = NULL; + /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */ +} + +/* #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 + +/* + * For systems with no strerror + */ + +#ifdef WIN32 +//extern int sys_nerr; +//extern char *sys_errlist[]; +#endif + +char * +SLIRPstrerror(error) + int error; +{ + if (error < sys_nerr) + return sys_errlist[error]; + else + return "Unknown error."; +} + +#endif + + +#ifdef _WIN32 + +int +fork_exec(so, ex, do_pty) + struct SLIRPsocket *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 SLIRPsocket *so; + char *ex; + int do_pty; +{ + int s; + struct sockaddr_in addr; + socklen_t 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 { + memset(&addr, 0, sizeof(struct sockaddr_in)); + 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(char *str) +{ + char *bptr; + + bptr = (char *)malloc(strlen(str)+1); + strcpy(bptr, str); + + return bptr; +} +#endif + +#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); +} + +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); +} +#endif + +int (*lprint_print) _P((void *, const char *, va_list)); +char *lprint_ptr, *lprint_ptr2, **lprint_arg; + +#ifdef _MSC_VER //aren't we +#define __STDC__ +#endif + +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 + 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); + else + bptr1++; + } + vfprintf(lfd, bptr2, args); + free(bptr2); + } + va_end(args); +} + +void +add_emu(buff) + char *buff; +{ + u_int lport, fport; + u_int8_t tos = 0, emu = 0; + char buff1[256], buff2[256], buff4[128]; + char *buff3 = buff4; + struct emu_t *emup; + struct SLIRPsocket *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) { + lprint("Error: Bad first argument\r\n"); + return; + } + } + + if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { + buff3 = 0; + if (sscanf(buff2, "%256s", buff1) != 1) { + lprint("Error: Bad second argument\r\n"); + return; + } + } + + if (buff3) { + if (strcmp(buff3, "lowdelay") == 0) + tos = IPTOS_LOWDELAY; + else if (strcmp(buff3, "throughput") == 0) + tos = IPTOS_THROUGHPUT; + else { + lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n"); + return; + } + } + + if (strcmp(buff1, "ftp") == 0) + emu = EMU_FTP; + else if (strcmp(buff1, "irc") == 0) + emu = EMU_IRC; + else if (strcmp(buff1, "none") == 0) + emu = EMU_NONE; /* ie: no emulation */ + else { + 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) { + lprint("Error: port already emulated\r\n"); + return; + } + } + + /* link it */ + emup = (struct emu_t *)malloc(sizeof (struct emu_t)); + emup->lport = (u_int16_t)lport; + emup->fport = (u_int16_t)fport; + emup->tos = tos; + 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)) || + (fport && fport == ntohs(so->so_fport))) { + if (emu) + so->so_emu = emu; + if (tos) + so->so_iptos = tos; + } + } + + lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); +} + +#ifdef BAD_SPRINTF + +#undef vsprintf +#undef sprintf + +/* + * Some BSD-derived systems have a sprintf which returns char * + */ + +int +vsprintf_len(string, format, args) + 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; +{ +#if defined USE_FIONBIO && defined FIONBIO + ioctlsockopt_t 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; +{ +#if defined USE_FIONBIO && defined FIONBIO + ioctlsockopt_t 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 SLIRPsocket *so; + struct SLIRPsocket *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/src/slirp/misc.h b/src/slirp/misc.h new file mode 100644 index 000000000..c509deb92 --- /dev/null +++ b/src/slirp/misc.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#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; + +#ifndef HAVE_STRDUP +char *strdup _P((const char *)); +#endif + +void do_wait _P((int)); + +#define EMU_NONE 0x0 + +/* TCP emulations */ +#define EMU_CTL 0x1 +#define EMU_FTP 0x2 +#define EMU_KSH 0x3 +#define EMU_IRC 0x4 +#define EMU_REALAUDIO 0x5 +#define EMU_RLOGIN 0x6 +#define EMU_IDENT 0x7 +#define EMU_RSH 0x8 + +#define EMU_NOCONNECT 0x10 /* Don't connect */ + +/* UDP emulations */ +#define EMU_TALK 0x1 +#define EMU_NTALK 0x2 +#define EMU_CUSEEME 0x3 + +struct tos_t { + u_int16_t lport; + u_int16_t fport; + u_int8_t tos; + u_int8_t emu; +}; + +struct emu_t { + u_int16_t lport; + u_int16_t fport; + u_int8_t tos; + u_int8_t emu; + struct emu_t *next; +}; + +extern struct emu_t *tcpemu; + +extern int x_port, x_server, x_display; + +int show_x _P((char *, struct SLIRPsocket *)); +void redir_x _P((u_int32_t, int, int, int)); +void getouraddr _P((void)); +void slirp_insque _P((void *, void *)); +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 SLIRPsocket *, 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 SLIRPsocket *, struct SLIRPsocket *, char *, char *, char *)); + +#endif diff --git a/src/slirp/queue.c b/src/slirp/queue.c new file mode 100644 index 000000000..d91004ad4 --- /dev/null +++ b/src/slirp/queue.c @@ -0,0 +1,116 @@ +/* + * File: queue.c + * Author: Robert I. Pitts + * Last Modified: March 9, 2000 + * Topic: Queue - Array Implementation + * ---------------------------------------------------------------- + */ + +#include +#include +#include "queue.h" + +/* + * Constants + * --------- + * MAX_QUEUE_SIZE = Largest number of items queue can hold. + */ + +#define MAX_QUEUE_SIZE 100 + +/* + * struct queueCDT gives the implementation of a queue. + * It holds the information that we need for each queue. + */ +typedef struct queueCDT { + queueElementT contents[MAX_QUEUE_SIZE]; + int front; + int count; +} queueCDT; + +queueADT QueueCreate(void) +{ + queueADT queue; + + queue = (queueADT)malloc(sizeof(queueCDT)); + + if (queue == NULL) { + fprintf(stderr, "Insufficient Memory for new Queue.\n"); + exit(ERROR_MEMORY); /* Exit program, returning error code. */ + } + + queue->front = 0; + queue->count = 0; + + return queue; +} + +void QueueDestroy(queueADT queue) +{ + free(queue); +} + +void QueueEnter(queueADT queue, queueElementT element) +{ + int newElementIndex; + + if (queue->count >= MAX_QUEUE_SIZE) { +// fprintf(stderr, "QueueEnter on Full Queue.\n"); +// exit(ERROR_QUEUE); /* Exit program, returning error code. */ + return; + } + + /* + * Calculate index at which to put + * next element. + */ + newElementIndex = (queue->front + queue->count) + % MAX_QUEUE_SIZE; + queue->contents[newElementIndex] = element; +//printf("element %d, pointer to %d, [%s]\n",newElementIndex,element,element); + + queue->count++; +} + +int QueuePeek(queueADT queue) +{ +return queue->count; +} + +queueElementT QueueDelete(queueADT queue) +{ + queueElementT oldElement; + + if (queue->count <= 0) { + //fprintf(stderr, "QueueDelete on Empty Queue.\n"); + //exit(ERROR_QUEUE); /* Exit program, returning error code. */ + return NULL; + } + + /* Save the element so we can return it. */ + oldElement = queue->contents[queue->front]; + + /* + * Advance the index of the front, + * making sure it wraps around the + * array properly. + */ + queue->front++; + queue->front %= MAX_QUEUE_SIZE; + +//printf("dequing @%d [%s]\n",oldElement,oldElement); + + queue->count--; + + return oldElement; +} + +int QueueIsEmpty(queueADT queue) +{ + return queue->count <= 0; +} + +int QueueIsFull(queueADT queue) +{ + return queue->count >= MAX_QUEUE_SIZE; +} diff --git a/src/slirp/queue.h b/src/slirp/queue.h new file mode 100644 index 000000000..534dcb84b --- /dev/null +++ b/src/slirp/queue.h @@ -0,0 +1,99 @@ +/* + * File: queue.h + * Author: Robert I. Pitts + * Last Modified: March 9, 2000 + * Topic: Queue - Array Implementation + * ---------------------------------------------------------------- + */ + +#ifndef _QUEUE_H +#define _QUEUE_H + +/* + * Constants + * --------- + * ERROR_* These signal error conditions in queue functions + * and are used as exit codes for the program. + */ +#define ERROR_QUEUE 2 +#define ERROR_MEMORY 3 + +/* + * Type: queueElementT + * ------------------- + * This is the type of objects held in the queue. + */ + +/*typedef char queueElementT; +typedef unsigned char *queueElementT; +*/ + +struct queuepacket{ + int len; + unsigned char data[2000]; +}; +typedef struct queuepacket *queueElementT; + +/* + * Type: queueADT + * -------------- + * The actual implementation of a queue is completely + * hidden. Client will work with queueADT which is a + * pointer to underlying queueCDT. + */ + +/* + * NOTE: need word struct below so that the compiler + * knows at least that a queueCDT will be some sort + * of struct. + */ + +typedef struct queueCDT *queueADT; + +/* + * Function: QueueCreate + * Usage: queue = QueueCreate(); + * ------------------------- + * A new empty queue is created and returned. + */ + +queueADT QueueCreate(void); + +/* Function: QueueDestroy + * Usage: QueueDestroy(queue); + * ----------------------- + * This function frees all memory associated with + * the queue. "queue" may not be used again unless + * queue = QueueCreate() is called first. + */ + +void QueueDestroy(queueADT queue); + +/* + * Functions: QueueEnter, QueueDelete + * Usage: QueueEnter(queue, element); + * element = QueueDelete(queue); + * -------------------------------------------- + * These are the fundamental queue operations that enter + * elements in and delete elements from the queue. A call + * to QueueDelete() on an empty queue or to QueueEnter() + * on a full queue is an error. Make use of QueueIsFull() + * and QueueIsEmpty() (see below) to avoid these errors. + */ + +void QueueEnter(queueADT queue, queueElementT element); +queueElementT QueueDelete(queueADT queue); + + +/* + * Functions: QueueIsEmpty, QueueIsFull + * Usage: if (QueueIsEmpty(queue)) ... + * ----------------------------------- + * These return a true/false value based on whether + * the queue is empty or full, respectively. + */ + +int QueueIsEmpty(queueADT queue); +int QueueIsFull(queueADT queue); + +#endif /* not defined _QUEUE_H */ diff --git a/src/slirp/sbuf.c b/src/slirp/sbuf.c new file mode 100644 index 000000000..b9baa4181 --- /dev/null +++ b/src/slirp/sbuf.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "slirp.h" + +/* Done as a macro in socket.h */ +/* int + * sbspace(struct sockbuff *sb) + * { + * return SB_DATALEN - sb->sb_cc; + * } + */ + +void +sbfree(sb) + struct sbuf *sb; +{ + free(sb->sb_data); +} + +void +sbdrop(sb, num) + struct sbuf *sb; + int num; +{ + /* + * We can only drop how much we have + * This should never succeed + */ + if(num > sb->sb_cc) + num = sb->sb_cc; + sb->sb_cc -= num; + sb->sb_rptr += num; + if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) + sb->sb_rptr -= sb->sb_datalen; + +} + +void +sbreserve(sb, size) + struct 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; + } +} + +/* + * Try and write() to the socket, whatever doesn't get written + * append to the buffer... for a host with a fast net connection, + * this prevents an unnecessary copy of the data + * (the socket is non-blocking, so we won't hang) + */ +void +sbappend(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + int ret = 0; + + DEBUG_CALL("sbappend"); + 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); + return; + } + + /* + * If there is urgent data, call sosendoob + * if not all was sent, sowrite will take care of the rest + * (The rest of this function is just an optimisation) + */ + if (so->so_urgc) { + sbappendsb(&so->so_rcv, m); + m_free(m); + sosendoob(so); + return; + } + + /* + * 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 (ret <= 0) { + /* + * Nothing was written + * It's possible that the socket has closed, but + * 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); + } else if (ret != m->m_len) { + /* + * Something was written, but not everything.. + * sbappendsb the rest + */ + m->m_len -= ret; + m->m_data += ret; + sbappendsb(&so->so_rcv, m); + } /* else */ + /* Whatever happened, we free the SLIRPmbuf */ + m_free(m); +} + +/* + * Copy the data from m into sb + * The caller is responsible to make sure there's enough room + */ +void +sbappendsb(sb, m) + struct sbuf *sb; + struct SLIRPmbuf *m; +{ + int len, n, nn; + + len = m->m_len; + + if (sb->sb_wptr < sb->sb_rptr) { + n = sb->sb_rptr - sb->sb_wptr; + if (n > len) n = len; + memcpy(sb->sb_wptr, m->m_data, n); + } else { + /* Do the right edge first */ + n = sb->sb_data + sb->sb_datalen - sb->sb_wptr; + if (n > len) n = len; + memcpy(sb->sb_wptr, m->m_data, n); + len -= n; + if (len) { + /* Now the left edge */ + nn = sb->sb_rptr - sb->sb_data; + if (nn > len) nn = len; + memcpy(sb->sb_data,m->m_data+n,nn); + n += nn; + } + } + + sb->sb_cc += n; + sb->sb_wptr += n; + if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) + sb->sb_wptr -= sb->sb_datalen; +} + +/* + * Copy data from sbuf to a normal, straight buffer + * Don't update the sbuf rptr, this will be + * done in sbdrop when the data is acked + */ +void +sbcopy(sb, off, len, to) + struct sbuf *sb; + int off; + int len; + char *to; +{ + char *from; + + from = sb->sb_rptr + off; + if (from >= sb->sb_data + sb->sb_datalen) + from -= sb->sb_datalen; + + if (from < sb->sb_wptr) { + if (len > sb->sb_cc) len = sb->sb_cc; + memcpy(to,from,len); + } else { + /* re-use off */ + off = (sb->sb_data + sb->sb_datalen) - from; + if (off > len) off = len; + memcpy(to,from,off); + len -= off; + if (len) + memcpy(to+off,sb->sb_data,len); + } +} + diff --git a/src/slirp/sbuf.h b/src/slirp/sbuf.h new file mode 100644 index 000000000..aa4724df7 --- /dev/null +++ b/src/slirp/sbuf.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _SBUF_H_ +#define _SBUF_H_ + +#define sbflush(sb) sbdrop((sb),(sb)->sb_cc) +#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) + +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 */ +}; + +void sbfree _P((struct sbuf *)); +void sbdrop _P((struct sbuf *, int)); +void sbreserve _P((struct sbuf *, int)); +void sbappend _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +void sbappendsb _P((struct sbuf *, struct SLIRPmbuf *)); +void sbcopy _P((struct sbuf *, int, int, char *)); + +#endif diff --git a/src/slirp/slirp.c b/src/slirp/slirp.c new file mode 100644 index 000000000..dc912c960 --- /dev/null +++ b/src/slirp/slirp.c @@ -0,0 +1,682 @@ +#include "slirp.h" + +/* host address */ +struct in_addr our_addr; +/* host dns address */ +struct in_addr dns_addr; +/* host loopback address */ +struct in_addr loopback_addr; + +/* address for slirp virtual addresses */ +struct in_addr special_addr; +/* virtual address alias for host */ +struct in_addr alias_addr; + +const uint8_t special_ethaddr[6] = { + 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 +}; + +uint8_t client_ethaddr[6]; + +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]; + +#ifdef _WIN32 + +static int get_dns_addr(struct in_addr *pdns_addr) +{ + FIXED_INFO *FixedInfo=NULL; + ULONG BufLen; + DWORD ret; + IP_ADDR_STRING *pIPAddr; + struct in_addr tmp_addr; + + FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); + BufLen = sizeof(FIXED_INFO); + + if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + FixedInfo = GlobalAlloc(GPTR, BufLen); + } + + if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { + printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + return -1; + } + + 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; + } +#endif + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + return 0; +} + +#else + +static int get_dns_addr(struct in_addr *pdns_addr) +{ + char buff[512]; + char buff2[256]; + FILE *f; + int found = 0; + struct in_addr tmp_addr; + + f = fopen("/etc/resolv.conf", "r"); + if (!f) + return -1; + + lprint("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)"); + break; + } else + lprint("%s", inet_ntoa(tmp_addr)); + } + } + fclose(f); + if (!found) + return -1; + return 0; +} + +#endif + +#ifdef _WIN32 +void slirp_cleanup(void) +{ + WSACleanup(); +} +#endif + +int slirp_init(void) +{ +#ifdef SLIRP_DEBUG + // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); + // debug_init("slirplog.txt",DEBUG_DEFAULT); + //debug_init("slirplog.txt",DBG_CALL); +debug_init("slirplog.txt",DEBUG_DEFAULT); +#endif + +#ifdef _WIN32 + { + WSADATA Data; + WSAStartup(MAKEWORD(2,0), &Data); + atexit(slirp_cleanup); + } +#endif + + link_up = 1; + + if_init(); + ip_init(); + + /* Initialise mbufs *after* setting the MTU */ + m_init(); + + /* set default addresses */ + inet_aton("127.0.0.1", &loopback_addr); + + if (get_dns_addr(&dns_addr) < 0) + return -1; + + inet_aton(CTL_SPECIAL, &special_addr); + alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); + getouraddr(); + return 0; +} + +#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) +#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) +#define UPD_NFDS(x) if (nfds < (x)) nfds = (x) + +/* + * curtime kept to an accuracy of 1ms + */ +#ifdef _WIN32 +static void updtime(void) +{ + struct _timeb tb; + + _ftime(&tb); + curtime = (u_int)tb.time * (u_int)1000; + curtime += (u_int)tb.millitm; +} +#else +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 + +int slirp_select_fill(int *pnfds, + fd_set *readfds, fd_set *writefds, fd_set *xfds) +{ + struct SLIRPsocket *so, *so_next; + int nfds; + int timeout, tmp_time; + + /* fail safe */ + 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(&so->so_tcpcb->t_flags!=0x0){ //This is to prevent a common lockup. + 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) { + 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 + */ + + timeout = -1; + + /* + * If a slowtimo is needed, set timeout to 5ms from the last + * slow timeout. If a fast timeout is needed, set timeout within + * 2ms of when it was requested. + */ +# define SLOW_TIMO 5 +# define FAST_TIMO 2 + if (do_slowtimo) { + timeout = (SLOW_TIMO - (curtime - last_slowtimo)) * 1000; + if (timeout < 0) + timeout = 0; + else if (timeout > (SLOW_TIMO * 1000)) + timeout = SLOW_TIMO * 1000; + + /* Can only fasttimo if we also slowtimo */ + if (time_fasttimo) { + tmp_time = (FAST_TIMO - (curtime - time_fasttimo)) * 1000; + if (tmp_time < 0) + tmp_time = 0; + + /* Choose the smallest of the 2 */ + if (tmp_time < timeout) + timeout = tmp_time; + } + } + *pnfds = nfds; + + /* + * Adjust the timeout to make the minimum timeout + * 2ms (XXX?) to lessen the CPU load + */ + if (timeout < (FAST_TIMO * 1000)) + timeout = FAST_TIMO * 1000; + + return timeout; +} + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) +{ + struct SLIRPsocket *so, *so_next; + int ret; + + global_readfds = readfds; + global_writefds = writefds; + global_xfds = xfds; + + /* Update time */ + updtime(); + + /* + * See if anything has timed out + */ + if (link_up) { + if (time_fasttimo && ((curtime - time_fasttimo) >= FAST_TIMO)) { + tcp_fasttimo(); + time_fasttimo = 0; + } + if (do_slowtimo && ((curtime - last_slowtimo) >= SLOW_TIMO)) { + ip_slowtimo(); + tcp_slowtimo(); + last_slowtimo = curtime; + } + } + + /* + * Check sockets + */ + if (link_up) { + /* + * Check TCP sockets + */ + 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; + + /* + * Check for URG data + * This will soread as well, so no need to + * test for readfds below if this succeeds + */ + if (FD_ISSET(so->s, xfds)) + sorecvoob(so); + /* + * Check sockets for reading + */ + else if (FD_ISSET(so->s, readfds)) { + /* + * Check for incoming connections + */ + if (so->so_state & SS_FACCEPTCONN) { + tcp_connect(so); + continue; + } /* else */ + ret = soread(so); + + /* Output it if we read something */ + if (ret > 0) + tcp_output(sototcpcb(so)); + } + + /* + * Check sockets for writing + */ + if (FD_ISSET(so->s, writefds)) { + /* + * Check for non-blocking, still-connecting sockets + */ + if (so->so_state & SS_ISFCONNECTING) { + /* Connected */ + so->so_state &= ~SS_ISFCONNECTING; + + //ret = send(so->s, &ret, 0, 0); + //winsock2.h:549:32: note: expected 'const char *' but argument is of type 'int *' + //WINSOCK_API_LINKAGE int PASCAL send(SOCKET,const char*,int,int); JASON + //ret = send(so->s, "a", 1, 0); WHY THE HELL WAS THIS HERE?! + ret = send(so->s, &ret, 0, 0); //This is what it should be. + 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 SLIRPmbuf *)NULL, sizeof(struct ip), so); + /* continue; */ + } else + ret = sowrite(so); + /* + * 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 + */ +#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); + if (ret < 0) { + /* XXX */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; + /* else failed */ + so->so_state = SS_NOFDREF; + } else + so->so_state &= ~SS_ISFCONNECTING; + + } + tcp_input((struct SLIRPmbuf *)NULL, sizeof(struct ip),so); + } /* SS_ISFCONNECTING */ +#endif + } + + /* + * Now UDP sockets. + * Incoming packets are sent straight away, they're not buffered. + * Incoming UDP data isn't buffered either. + */ + for (so = udb.so_next; so != &udb; so = so_next) { + so_next = so->so_next; + + if (so->s != -1 && FD_ISSET(so->s, readfds)) { + sorecvfrom(so); + } + } + } + + /* + * See if we can start outputting + */ + if (if_queued && link_up) + if_start(); + + /* clear global file descriptor sets. + * these reside on the stack in vl.c + * so they're unusable if we're not in + * slirp_select_fill or slirp_select_poll. + */ + global_readfds = NULL; + global_writefds = NULL; + global_xfds = NULL; +} + +#define ETH_ALEN 6 +#define ETH_HLEN 14 + +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_ARP 0x0806 /* Address Resolution packet */ + +#define ARPOP_REQUEST 1 /* ARP request */ +#define ARPOP_REPLY 2 /* ARP reply */ + +struct ethhdr +{ + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + unsigned short h_proto; /* packet type ID field */ +}; + +struct arphdr +{ + unsigned short ar_hrd; /* format of hardware address */ + unsigned short ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + unsigned short ar_op; /* ARP opcode (command) */ + + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +}; + +void arp_input(const uint8_t *pkt, int pkt_len) +{ + struct ethhdr *eh = (struct ethhdr *)pkt; + struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN); + uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)]; + 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) + 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 */ + memcpy(client_ethaddr, eh->h_source, ETH_ALEN); + + /* ARP request for alias/dns mac address */ + memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); + reh->h_source[5] = ah->ar_tip[3]; + reh->h_proto = htons(ETH_P_ARP); + + rah->ar_hrd = htons(1); + rah->ar_pro = htons(ETH_P_IP); + rah->ar_hln = ETH_ALEN; + rah->ar_pln = 4; + rah->ar_op = htons(ARPOP_REPLY); + memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); + memcpy(rah->ar_sip, ah->ar_tip, 4); + memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); + memcpy(rah->ar_tip, ah->ar_sip, 4); + slirp_output(arp_reply, sizeof(arp_reply)); + } + break; + default: + break; + } +} + +void slirp_input(const uint8_t *pkt, int pkt_len) +{ + struct SLIRPmbuf *m; + int proto; + + if (pkt_len < ETH_HLEN) + return; + + proto = (pkt[12] << 8) | pkt[13]; + switch(proto) { + case ETH_P_ARP: + arp_input(pkt, pkt_len); + break; + case ETH_P_IP: + m = m_get(); + if (!m) + return; + /* Note: we add to align the IP header */ + m->m_len = pkt_len + 2; + memcpy(m->m_data + 2, pkt, pkt_len); + + m->m_data += 2 + ETH_HLEN; + m->m_len -= 2 + ETH_HLEN; + + ip_input(m); + break; + default: + break; + } +} + +/* output the IP packet to the ethernet device */ +void if_encap(const uint8_t *ip_data, int ip_data_len) +{ + uint8_t buf[1600]; + struct ethhdr *eh = (struct ethhdr *)buf; + + if (ip_data_len + ETH_HLEN > sizeof(buf)) + return; + + memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); + memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); + /* XXX: not correct */ + eh->h_source[5] = CTL_ALIAS; + eh->h_proto = htons(ETH_P_IP); + memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); + slirp_output(buf, ip_data_len + ETH_HLEN); +} + +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, + htons(guest_port), 0)) + return -1; + } else { + 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) +{ + return add_exec(&exec_list, do_pty, (char *)args, + addr_low_byte, htons(guest_port)); +} diff --git a/src/slirp/slirp.h b/src/slirp/slirp.h new file mode 100644 index 000000000..92cfe2fc9 --- /dev/null +++ b/src/slirp/slirp.h @@ -0,0 +1,415 @@ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#define SLIRP_VERSION "Cockatrice special" + +#define CONFIG_QEMU + +#ifndef CONFIG_QEMU +#include "version.h" +#endif +#include "config.h" +#include "slirp_config.h" + +#ifdef _WIN32 +#ifdef __GNUC__ //MINGW? +# include +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; +typedef char *SLIRPcaddr_t; +typedef int socklen_t; +typedef unsigned long ioctlsockopt_t; +#else +typedef unsigned char u_int8_t; +typedef char int8_t; +typedef unsigned char uint8_t; +typedef unsigned short u_int16_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned int u_int32_t; +typedef unsigned int uint32_t; +typedef int int32_t; + +typedef unsigned __int64 u_int64_t; +typedef char *SLIRPcaddr_t; +typedef int socklen_t; +typedef unsigned long ioctlsockopt_t; + +#endif + +# include //needs to be on top otherwise, it'll pull in winsock1 +# include + +# include +# include + +# define USE_FIONBIO 1 +# define EWOULDBLOCK WSAEWOULDBLOCK +# define EINPROGRESS WSAEINPROGRESS +# define ENOTCONN WSAENOTCONN +# define EHOSTUNREACH WSAEHOSTUNREACH +# define ENETUNREACH WSAENETUNREACH +# define ECONNREFUSED WSAECONNREFUSED + +/* Basilisk II Router defines those */ +# define udp_read_completion slirp_udp_read_completion +# define write_udp slirp_write_udp +# define init_udp slirp_init_udp +# define final_udp slirp_final_udp +#else +typedef int ioctlsockopt_t; +# define ioctlsocket ioctl +# define closesocket(s) close(s) +# define O_BINARY 0 +#endif + +#include +#ifdef HAVE_SYS_BITYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif + +#ifndef _MSC_VER +#include +#else +#include +#endif + +#ifdef NEED_TYPEDEFS +typedef char int8_t; +typedef unsigned char u_int8_t; + +# if SIZEOF_SHORT == 2 + typedef short int16_t; + typedef unsigned short u_int16_t; +# else +# if SIZEOF_INT == 2 + typedef int int16_t; + typedef unsigned int u_int16_t; +# else + #error Cannot find a type with sizeof() == 2 +# endif +# endif + +# if SIZEOF_SHORT == 4 + typedef short int32_t; + typedef unsigned short u_int32_t; +# else +# if SIZEOF_INT == 4 + typedef int int32_t; + typedef unsigned int u_int32_t; +# else + #error Cannot find a type with sizeof() == 4 +# endif +# endif +#endif /* NEED_TYPEDEFS */ + +/* Basilisk II types glue */ +typedef u_int8_t uint8; +typedef u_int16_t uint16; +typedef u_int32_t uint32; + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_STDLIB_H +# include +#endif + +#include +#include + +#ifndef HAVE_MEMMOVE +#define memmove(x, y, z) bcopy(y, x, z) +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifdef HAVE_STRING_H +# include +#else +#ifndef _MSC_VER +# include +#else +#include +#endif +#endif + +#ifndef _WIN32 +#include +#endif + +#ifndef _P +#ifndef NO_PROTOTYPES +# define _P(x) x +#else +# define _P(x) () +#endif +#endif + +#ifndef _WIN32 +#include +#include +#endif + +#ifdef GETTIMEOFDAY_ONE_ARG +#define gettimeofday(x, y) gettimeofday(x) +#endif + +/* Systems lacking strdup() definition in . */ +#if defined(ultrix) +char *strdup _P((const char *)); +#endif + +/* Systems lacking malloc() definition in . */ +#if defined(ultrix) || defined(hcx) +void *malloc _P((size_t arg)); +void free _P((void *ptr)); +#endif + +#ifndef HAVE_INET_ATON +int inet_aton _P((const char *cp, struct in_addr *ia)); +#endif + +#include +#ifndef NO_UNIX_SOCKETS +#include +#endif +#include +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif +#ifndef _WIN32 +#include +#endif + +#if defined(HAVE_SYS_IOCTL_H) +# include +#endif + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#ifdef HAVE_SYS_WAIT_H +# include +#endif + +#ifdef HAVE_SYS_FILIO_H +# include +#endif + +#ifdef USE_PPP +#include +#endif + +#ifdef __STDC__ +#include +#else +#include +#endif + +#include + +/* Avoid conflicting with the libc insque() and remque(), which + have different prototypes. */ +#define insque slirp_insque +#define remque slirp_remque + +#ifdef HAVE_SYS_STROPTS_H +#include +#endif + +#include "debug.h" + +#if defined __GNUC__ +#define PACKED__ __attribute__ ((packed)) +#elif defined __sgi +#define PRAGMA_PACK_SUPPORTED 1 +#define PACK_END 0 +#define PACKED__ +#elif _MSC_VER +//#define PRAGMA_PACK_SUPPORTED 1 +//#define PACK_END 4 +#define PACKED__ +#else +#error "Packed attribute or pragma shall be supported" +#endif + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +#include "ip.h" +#include "tcp.h" +#include "tcp_timer.h" +#include "tcp_var.h" +#include "tcpip.h" +#include "udp.h" +#include "icmp_var.h" +#include "mbuf.h" +#include "sbuf.h" +#include "socket.h" +#include "if.h" +#include "main.h" +#include "misc.h" +#include "ctl.h" +#ifdef USE_PPP +#include "ppp/pppd.h" +#include "ppp/ppp.h" +#endif + +#include "bootp.h" +#include "tftp.h" +#include "libslirp.h" + +extern struct ttys *ttys_unit[MAX_INTERFACES]; + +#ifndef NULL +#define NULL (void *)0 +#endif + +#ifndef FULL_BOLT +void if_start _P((void)); +#else +void if_start _P((struct ttys *)); +#endif + +#ifdef BAD_SPRINTF +# define vsprintf vsprintf_len +# define sprintf sprintf_len + extern int vsprintf_len _P((char *, const char *, va_list)); + extern int sprintf_len _P((char *, const char *, ...)); +#endif + +#ifdef DECLARE_SPRINTF +# ifndef BAD_SPRINTF + extern int vsprintf _P((char *, const char *, va_list)); +# endif + extern int vfprintf _P((FILE *, const char *, va_list)); +#endif + +#ifndef HAVE_STRERROR +#ifndef _MSC_VER + extern char *strerror _P((int error)); + #define HAVE_STRERROR +#endif +#endif + +#ifndef HAVE_INDEX + char *index _P((const char *, int)); +#endif + +#ifndef HAVE_GETHOSTID + long gethostid _P((void)); +#endif + +void lprint _P((const char *, ...)); + +extern int do_echo; + +#ifdef _MSC_VER +#define inline +#endif + +#if SIZEOF_CHAR_P == 4 +# define insque_32 insque +# define remque_32 remque +#else + extern inline void insque_32 _P((void *, void *)); + extern inline void remque_32 _P((void *)); +#endif + +#ifndef _WIN32 +#include +#endif + +#define DEFAULT_BAUD 115200 + +/* cksum.c */ +int cksum(struct SLIRPmbuf *m, int len); + +/* if.c */ +void if_init _P((void)); +void if_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); + +/* ip_input.c */ +void ip_init _P((void)); +void ip_input _P((struct SLIRPmbuf *)); +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 SLIRPmbuf *, struct SLIRPmbuf *)); + +/* ip_output.c */ +int ip_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); + +/* tcp_input.c */ +int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct SLIRPmbuf *)); +void tcp_input _P((register struct SLIRPmbuf *, int, struct SLIRPsocket *)); +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)); + +/* tcp_output.c */ +int tcp_output _P((register struct tcpcb *)); +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 SLIRPmbuf *, tcp_seq, tcp_seq, int)); +struct tcpcb * tcp_newtcpcb _P((struct SLIRPsocket *)); +struct tcpcb * tcp_close _P((register struct tcpcb *)); +void tcp_drain _P((void)); +void tcp_sockclosed _P((struct tcpcb *)); +int tcp_fconnect _P((struct SLIRPsocket *)); +void tcp_connect _P((struct SLIRPsocket *)); +int tcp_attach _P((struct SLIRPsocket *)); +u_int8_t tcp_tos _P((struct SLIRPsocket *)); +int tcp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +int tcp_ctl _P((struct SLIRPsocket *)); +struct tcpcb *tcp_drop(struct tcpcb *tp, int err); + + +#if defined(_MSC_VER) +#pragma pack(pop) +#endif + +#ifdef USE_PPP +#define MIN_MRU MINMRU +#define MAX_MRU MAXMRU +#else +#define MIN_MRU 128 +#define MAX_MRU 16384 +#endif + +#ifndef _WIN32 +#define min(x,y) ((x) < (y) ? (x) : (y)) +#define max(x,y) ((x) > (y) ? (x) : (y)) +#endif + +#ifdef _WIN32 +#undef errno +#define errno (WSAGetLastError()) +#endif + +#define PROBE_CONN + +#endif diff --git a/src/slirp/slirp_config.h b/src/slirp/slirp_config.h new file mode 100644 index 000000000..e583dcc80 --- /dev/null +++ b/src/slirp/slirp_config.h @@ -0,0 +1,135 @@ +/* + * User definable configuration options + */ + +/* Undefine if you don't want talk emulation */ +#undef EMULATE_TALK + +/* Define if you want the connection to be probed */ +/* XXX Not working yet, so ignore this for now */ +#undef PROBE_CONN + +/* Define to 1 if you want KEEPALIVE timers */ +#define DO_KEEPALIVE 0 + +/* Define to MAX interfaces you expect to use at once */ +/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */ +/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */ +#define MAX_INTERFACES 1 +#define MAX_PPP_INTERFACES 1 + +/* Define if you want slirp's socket in /tmp */ +/* XXXXXX Do this in ./configure */ +#undef USE_TMPSOCKET + +/* Define if you want slirp to use cfsetXspeed() on the terminal */ +#undef DO_CFSETSPEED + +/* Define this if you want slirp to write to the tty as fast as it can */ +/* This should only be set if you are using load-balancing, slirp does a */ +/* pretty good job on single modems already, and seting this will make */ +/* interactive sessions less responsive */ +/* XXXXX Talk about having fast modem as unit 0 */ +#undef FULL_BOLT + +/* + * Define if you want slirp to use less CPU + * You will notice a small lag in interactive sessions, but it's not that bad + * Things like Netscape/ftp/etc. are completely unaffected + * This is mainly for sysadmins who have many slirp users + */ +#undef USE_LOWCPU + +/* Define this if your compiler doesn't like prototypes */ +#ifndef __STDC__ +#define NO_PROTOTYPES +#endif + +/*********************************************************/ +/* + * Autoconf defined configuration options + * You shouldn't need to touch any of these + */ + +/* Ignore this */ +#undef DUMMY_PPP + +/* XXX: Define according to how time.h should be included */ +#undef TIME_WITH_SYS_TIME +#define TIME_WITH_SYS_TIME 0 +#undef HAVE_SYS_TIME_H + +/* Define if your sprintf returns char * instead of int */ +#undef BAD_SPRINTF + +/* Define if you have readv */ +#undef HAVE_READV + +/* Define if iovec needs to be declared */ +#undef DECLARE_IOVEC +#ifdef _WIN32 +#define DECLARE_IOVEC +#endif + +/* Define if a declaration of sprintf/fprintf is needed */ +#undef DECLARE_SPRINTF + +/* Define if you have sys/stropts.h */ +#undef HAVE_SYS_STROPTS_H + +/* Define if your compiler doesn't like prototypes */ +#undef NO_PROTOTYPES + +/* Define if you don't have u_int32_t etc. typedef'd */ +#undef NEED_TYPEDEFS +#ifdef __sun__ +#define NEED_TYPEDEFS +#endif + +/* Define to sizeof(char *) */ +#define SIZEOF_CHAR_P SIZEOF_VOID_P + +/* Define if you have random() */ +#undef HAVE_RANDOM + +/* Define if you have srandom() */ +#undef HAVE_SRANDOM + +/* Define if you have setenv */ +#undef HAVE_SETENV + +/* Define if you have index() */ +#undef HAVE_INDEX + +/* Define if you have bcmp() */ +#undef HAVE_BCMP + +/* Define if you have drand48 */ +#undef HAVE_DRAND48 + +/* Define if you have memmove */ +#define HAVE_MEMMOVE + +/* Define if you have gethostid */ +#undef HAVE_GETHOSTID + +/* Define if you DON'T have unix-domain sockets */ +#undef NO_UNIX_SOCKETS +#ifdef _WIN32 +#define NO_UNIX_SOCKETS +#endif + +/* Define if gettimeofday only takes one argument */ +#undef GETTIMEOFDAY_ONE_ARG + +/* Define if you have revoke() */ +#undef HAVE_REVOKE + +/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */ +#undef HAVE_GRANTPT + +/* Define if you have fchmod */ +#undef HAVE_FCHMOD + +/* Define if you have */ +#undef HAVE_SYS_TYPES32_H diff --git a/src/slirp/socket.c b/src/slirp/socket.c new file mode 100644 index 000000000..5e6fb2dc0 --- /dev/null +++ b/src/slirp/socket.c @@ -0,0 +1,731 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#include "slirp.h" +#include "ip_icmp.h" +#include "main.h" +#ifdef __sun__ +#include +#endif + +#ifndef FIONREAD +#include +#endif + +void +so_init() +{ + /* Nothing yet */ +} + + +struct SLIRPsocket * +solookup(head, laddr, lport, faddr, fport) + struct SLIRPsocket *head; + struct in_addr laddr; + u_int lport; + struct in_addr faddr; + u_int fport; +{ + struct SLIRPsocket *so; + + for (so = head->so_next; so != head; so = so->so_next) { + 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 SLIRPsocket *)NULL; + return so; + +} + +/* + * Create a new socket, initialise the fields + * It is the responsibility of the caller to + * insque() it into the correct linked-list + */ +struct SLIRPsocket * +socreate() +{ + struct SLIRPsocket *so; + + so = (struct SLIRPsocket *)malloc(sizeof(struct SLIRPsocket)); + if(so) { + memset(so, 0, sizeof(struct SLIRPsocket)); + so->so_state = SS_NOFDREF; + so->s = -1; + } + return(so); +} + +/* + * remque and free a socket, clobber cache + */ +void +sofree(so) + struct SLIRPsocket *so; +{ + if (so->so_emu==EMU_RSH && so->extra) { + sofree(so->extra); + so->extra=NULL; + } + if (so == tcp_last_so) + tcp_last_so = &tcb; + else if (so == udp_last_so) + udp_last_so = &udb; + + if(so->so_m!=NULL) + m_free(so->so_m); + + if(so->so_next && so->so_prev) + remque(so); /* crashes if so is not in a queue */ + + free(so); +} + +/* + * Read from so's socket into sb_snd, updating all relevant sbuf fields + * NOTE: This will only be called if it is select()ed for reading, so + * a read() of 0 (or less) means it's disconnected + */ +int +soread(so) + struct SLIRPsocket *so; +{ + int n, nn, lss, total; + struct sbuf *sb = &so->so_snd; + int len = sb->sb_datalen - sb->sb_cc; + struct iovec iov[2]; + int mss; + if(!so->so_tcpcb) + return 0; + + 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; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) + iov[0].iov_len = len; + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len%mss; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_rptr - sb->sb_data; + if(iov[1].iov_len > len) + iov[1].iov_len = len; + total = iov[0].iov_len + iov[1].iov_len; + if (total > mss) { + lss = total%mss; + if (iov[1].iov_len > lss) { + iov[1].iov_len -= lss; + n = 2; + } else { + lss -= iov[1].iov_len; + iov[0].iov_len -= lss; + n = 1; + } + } else + n = 2; + } else { + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len%mss; + 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 + if (nn <= 0) { + if (nn < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + else { + DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno))); + sofcantrcvmore(so); + tcp_sockclosed(sototcpcb(so)); + return -1; + } + } + +#ifndef HAVE_READV + /* + * If there was no error, try and read the second time round + * We read again if n = 2 (ie, there's another part of the buffer) + * and we read as much as we could in the first read + * We don't test for <= 0 this time, because there legitimately + * might not be any more data (since the socket is non-blocking), + * a close will be detected on next iteration. + * A return of -1 wont (shouldn't) happen, since it didn't happen above + */ + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0); + 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; + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) + 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 + */ +void +sorecvoob(so) + struct SLIRPsocket *so; +{ + struct tcpcb *tp = sototcpcb(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. + */ + soread(so); + tp->snd_up = tp->snd_una + so->so_snd.sb_cc; + tp->t_force = 1; + tcp_output(tp); + tp->t_force = 0; +} + +/* + * Send urgent data + * There's a lot duplicated code here, but... + */ +int +sosendoob(so) + struct SLIRPsocket *so; +{ + struct 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 + */ + len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (len > so->so_urgc) len = so->so_urgc; + memcpy(buff, sb->sb_rptr, len); + so->so_urgc -= len; + if (so->so_urgc) { + n = sb->sb_wptr - sb->sb_data; + if (n > so->so_urgc) n = so->so_urgc; + memcpy((buff + len), sb->sb_data, n); + so->so_urgc -= n; + len += n; + } + n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ +#ifdef SLIRP_DEBUG + if (n != len) + DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); +#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, + * updating all sbuf field as necessary + */ +int +sowrite(so) + struct SLIRPsocket *so; +{ + int n,nn; + struct 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) + return 0; + } + + /* + * 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; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) iov[0].iov_len = len; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (iov[0].iov_len > len) iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_wptr - sb->sb_data; + if (iov[1].iov_len > len) iov[1].iov_len = len; + n = 2; + } else + n = 1; + } + /* Check if there's urgent data to send, and if so, send it */ + +#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); +#endif + /* 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)); + sofcantsendmore(so); + tcp_sockclosed(sototcpcb(so)); + return -1; + } + +#ifndef HAVE_READV + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0); + if (ret > 0) + nn += ret; + } + 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; +} + +/* + * recvfrom() a UDP socket + */ +void +sorecvfrom(so) + struct SLIRPsocket *so; +{ + struct sockaddr_in addr; + socklen_t 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, + (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! */ + } + /* No need for this socket anymore, udp_detach it */ + udp_detach(so); + } else { /* A "normal" UDP packet */ + struct SLIRPmbuf *m; + int len; + ioctlsockopt_t n; + + if (!(m = m_get())) 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); + /* 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); + } + /* } */ + + 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", + 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); + } else { + /* + * Hack: domain name lookup will be used the most for UDP, + * and since they'll only be used once there's no need + * for the 4 minute (or whatever) timeout... So we time them + * out much quicker (10 seconds for now...) + */ + if (so->so_expire) { + if (so->so_fport == htons(53)) + so->so_expire = curtime + SO_EXPIREFAST; + else + so->so_expire = curtime + SO_EXPIRE; + } + + /* if (m->m_len == len) { + * m_inc(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 + */ + udp_output(so, m, &addr); + } /* rx error */ + } /* if ping packet */ +} + +/* + * sendto() a socket + */ +int +sosendto(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + int ret; + struct sockaddr_in addr; + + 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; + } + } 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 + */ + if (so->so_expire) + so->so_expire = curtime + SO_EXPIRE; + so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */ + return 0; +} + +/* + * XXX This should really be tcp_listen + */ +struct SLIRPsocket * +solisten(port, laddr, lport, flags) + u_int port; + u_int32_t laddr; + u_int lport; + int flags; +{ + struct sockaddr_in addr; + struct SLIRPsocket *so; + int s; + socklen_t addrlen = sizeof(addr); + int opt = 1; + + DEBUG_CALL("solisten"); + DEBUG_ARG("port = %d", port); + 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_laddr.s_addr = laddr; /* Ditto */ + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + 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) || + (listen(s,1) < 0)) { + int tmperrno = errno; /* Don't clobber the real reason we failed */ + + close(s); + sofree(so); + /* Restore the real errno */ +#ifdef _WIN32 + WSASetLastError(tmperrno); +#else + errno = tmperrno; +#endif + return NULL; + } + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + + 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) + so->so_faddr = alias_addr; + else + so->so_faddr = addr.sin_addr; + + so->s = s; + return so; +} + +/* + * Data is available in so_rcv + * Just write() the data to the socket + * XXX not yet... + */ +void +sorwakeup(so) + struct SLIRPsocket *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 + * For now, don't read, it'll be done in the main loop + */ +void +sowwakeup(so) + struct SLIRPsocket *so; +{ + /* Nothing, yet */ +} + +/* + * Various session state calls + * XXX Should be #define's + * The socket state stuff needs work, these often get call 2 or 3 + * times each when only 1 was needed + */ +void +soisfconnecting(so) + register struct SLIRPsocket *so; +{ + so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE| + SS_FCANTSENDMORE|SS_FWDRAIN); + so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ +} + +void +soisfconnected(so) + register struct SLIRPsocket *so; +{ + so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF); + so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ +} + +void +sofcantrcvmore(so) + struct SLIRPsocket *so; +{ + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s,0); + if(global_writefds) { + FD_CLR(so->s,global_writefds); + } + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTSENDMORE) + so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */ + else + so->so_state |= SS_FCANTRCVMORE; +} + +void +sofcantsendmore(so) + struct SLIRPsocket *so; +{ + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s,1); /* send FIN to fhost */ + if (global_readfds) { + FD_CLR(so->s,global_readfds); + } + if (global_xfds) { + FD_CLR(so->s,global_xfds); + } + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTRCVMORE) + so->so_state = SS_NOFDREF; /* as above */ + else + so->so_state |= SS_FCANTSENDMORE; +} + +void +soisfdisconnected(so) + struct SLIRPsocket *so; +{ +/* so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */ +/* close(so->s); */ +/* so->so_state = SS_ISFDISCONNECTED; */ + /* + * XXX Do nothing ... ? + */ +} + +/* + * Set write drain mode + * Set CANTSENDMORE once all data has been write()n + */ +void +sofwdrain(so) + struct SLIRPsocket *so; +{ + if (so->so_rcv.sb_cc) + so->so_state |= SS_FWDRAIN; + else + sofcantsendmore(so); +} + diff --git a/src/slirp/socket.h b/src/slirp/socket.h new file mode 100644 index 000000000..3a777934a --- /dev/null +++ b/src/slirp/socket.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +/* MINE */ + +#ifndef _SLIRP_SOCKET_H_ +#define _SLIRP_SOCKET_H_ + +#define SO_EXPIRE 240000 +#define SO_EXPIREFAST 10000 + +/* + * Our socket structure + */ + +struct SLIRPsocket { + struct SLIRPsocket *so_next,*so_prev; /* For a linked list of sockets */ + + int s; /* The actual socket */ + + /* XXX union these with not-yet-used sbuf params */ + struct SLIRPmbuf *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 + * so_mconn, for non-blocking connections */ + int so_urgc; + struct in_addr so_faddr; /* foreign host table entry */ + struct in_addr so_laddr; /* local host table entry */ + u_int16_t so_fport; /* foreign port */ + u_int16_t so_lport; /* local port */ + + 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 */ + void * extra; /* Extra pointer */ +}; + + +/* + * Socket state bits. (peer means the host on the Internet, + * local host means the host on the other end of the modem) + */ +#define SS_NOFDREF 0x001 /* No fd reference */ + +#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ +#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ +#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */ +#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */ +/* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */ +#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ + +#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 */ + +extern struct SLIRPsocket tcb; + + +#if defined(DECLARE_IOVEC) && !defined(HAVE_READV) +struct iovec { + char *iov_base; + size_t iov_len; +}; +#endif + +void so_init _P((void)); +struct SLIRPsocket * solookup _P((struct SLIRPsocket *, struct in_addr, u_int, struct in_addr, u_int)); +struct SLIRPsocket * socreate _P((void)); +void sofree _P((struct SLIRPsocket *)); +int soread _P((struct SLIRPsocket *)); +void sorecvoob _P((struct SLIRPsocket *)); +int sosendoob _P((struct SLIRPsocket *)); +int sowrite _P((struct SLIRPsocket *)); +void sorecvfrom _P((struct SLIRPsocket *)); +int sosendto _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +struct SLIRPsocket * solisten _P((u_int, u_int32_t, u_int, int)); +void sorwakeup _P((struct SLIRPsocket *)); +void sowwakeup _P((struct SLIRPsocket *)); +void soisfconnecting _P((register struct SLIRPsocket *)); +void soisfconnected _P((register struct SLIRPsocket *)); +void sofcantrcvmore _P((struct SLIRPsocket *)); +void sofcantsendmore _P((struct SLIRPsocket *)); +void soisfdisconnected _P((struct SLIRPsocket *)); +void sofwdrain _P((struct SLIRPsocket *)); + +#endif /* _SOCKET_H_ */ diff --git a/src/slirp/tcp.h b/src/slirp/tcp.h new file mode 100644 index 000000000..38c41bbf2 --- /dev/null +++ b/src/slirp/tcp.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp.h 8.1 (Berkeley) 6/10/93 + * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp + */ + +#ifndef _TCP_H_ +#define _TCP_H_ + +typedef u_int32_t tcp_seq; + +#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ +#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ + +extern int tcp_rcvspace; +extern int tcp_sndspace; +extern struct SLIRPsocket *tcp_last_so; + +#define TCP_SNDSPACE 8192 +#define TCP_RCVSPACE 8192 + +/* + * TCP header. + * Per RFC 793, September, 1981. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct tcphdr { + u_int16_t th_sport; /* source port */ + u_int16_t th_dport; /* destination port */ + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ +#ifdef WORDS_BIGENDIAN + u_char th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#else + u_char th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#endif + u_int8_t th_flags; +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 + u_int16_t th_win; /* window */ + u_int16_t th_sum; /* checksum */ + u_int16_t th_urp; /* urgent pointer */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +#include "tcp_var.h" + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOLEN_MAXSEG 4 +#define TCPOPT_WINDOW 3 +#define TCPOLEN_WINDOW 3 +#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOPT_SACK 5 /* Experimental */ +#define TCPOPT_TIMESTAMP 8 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ + +#define TCPOPT_TSTAMP_HDR \ + (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) + +/* + * Default maximum segment size for TCP. + * With an IP MSS of 576, this is 536, + * but 512 is probably more convenient. + * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). + * + * We make this 1460 because we only care about Ethernet in the qemu context. + */ +#define TCP_MSS 1460 + +#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ + +#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ + +/* + * User-settable options (used with setsockopt). + * + * We don't use the system headers on unix because we have conflicting + * local structures. We can't avoid the system definitions on Windows, + * so we undefine them. + */ +#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 */ + +/* + * TCP FSM state definitions. + * Per RFC793, September, 1981. + */ + +#define TCP_NSTATES 11 + +#define TCPS_CLOSED 0 /* closed */ +#define TCPS_LISTEN 1 /* listening for connection */ +#define TCPS_SYN_SENT 2 /* active, have sent syn */ +#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ +/* states < TCPS_ESTABLISHED are those where connections not established */ +#define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ +/* states > TCPS_CLOSE_WAIT are those where user has closed */ +#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ +#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ +/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ +#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ + +#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) +#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) +#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) + +/* + * TCP sequence numbers are 32 bit integers operated + * on with modular arithmetic. These macros can be + * used to compare such integers. + */ +#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) +#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) +#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * Macros to initialize tcp sequence numbers for + * send and receive from initial send and receive + * sequence numbers. + */ +#define tcp_rcvseqinit(tp) \ + (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 + +#define tcp_sendseqinit(tp) \ + (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss + +#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ + +extern tcp_seq tcp_iss; /* tcp initial send seq # */ + +extern char *tcpstates[]; + +#endif diff --git a/src/slirp/tcp_input.c b/src/slirp/tcp_input.c new file mode 100644 index 000000000..77006a2d7 --- /dev/null +++ b/src/slirp/tcp_input.c @@ -0,0 +1,1722 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_input.c 8.5 (Berkeley) 4/10/94 + * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "slirp.h" +#include "ip_icmp.h" + +struct SLIRPsocket tcb; + +int tcprexmtthresh = 3; +struct SLIRPsocket *tcp_last_so = &tcb; + +tcp_seq tcp_iss; /* tcp initial send seq # */ + +#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) + +/* for modulo comparisons of timestamps */ +#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) +#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * Insert segment ti into reassembly queue of tcp with + * control block tp. Return TH_FIN if reassembly now includes + * a segment with FIN. The macro form does the common case inline + * (segment is the next to be received on an established connection, + * and the queue is empty), avoiding linkage into and removal + * from the queue and repetition of various conversions. + * Set DELACK for segments received in order, but ack immediately + * when segments are out of order (so fast retransmit can work). + */ +#ifdef TCP_ACK_HACK +#define TCP_REASS(tp, ti, m, so, flags) {\ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) {\ + if (ti->ti_flags & TH_PUSH) \ + tp->t_flags |= TF_ACKNOW; \ + else \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + if (so->so_emu) { \ + if (tcp_emu((so),(m))) sbappend((so), (m)); \ + } else \ + sbappend((so), (m)); \ +/* sorwakeup(so); */ \ + } else {\ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#else +#define TCP_REASS(tp, ti, m, so, flags) { \ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) { \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + if (so->so_emu) { \ + if (tcp_emu((so),(m))) sbappend(so, (m)); \ + } else \ + sbappend((so), (m)); \ +/* sorwakeup(so); */ \ + } else { \ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#endif + +int +tcp_reass(tp, ti, m) + struct tcpcb *tp; + struct tcpiphdr *ti; + struct SLIRPmbuf *m; +{ + struct tcpiphdr *q; + struct SLIRPsocket *so = tp->t_socket; + int flags; + + /* + * Call with ti==0 after become established to + * force pre-ESTABLISHED data up to user socket. + */ + if (ti == 0) + goto present; + + /* + * Find a segment which begins after this one does. + */ + for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp; + q = (struct tcpiphdr *)q->ti_next) + if (SEQ_GT(q->ti_seq, ti->ti_seq)) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { + int i; + q = (struct tcpiphdr *)q->ti_prev; + /* conversion to int (in i) handles seq wraparound */ + i = q->ti_seq + q->ti_len - ti->ti_seq; + if (i > 0) { + if (i >= ti->ti_len) { + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += ti->ti_len; + m_freem(m); + /* + * Try to present any queued data + * at the left window edge to the user. + * This is needed after the 3-WHS + * completes. + */ + goto present; /* ??? */ + } + m_adj(m, i); + ti->ti_len -= i; + ti->ti_seq += i; + } + q = (struct tcpiphdr *)(q->ti_next); + } + tcpstat.tcps_rcvoopack++; + tcpstat.tcps_rcvoobyte += ti->ti_len; + REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct tcpiphdr *)tp) { + int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; + if (i <= 0) + break; + if (i < q->ti_len) { + q->ti_seq += i; + q->ti_len -= i; + m_adj((struct SLIRPmbuf *) REASS_MBUF(q), i); + break; + } + q = (struct tcpiphdr *)q->ti_next; + m = (struct SLIRPmbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev); + remque_32((void *)(q->ti_prev)); + m_freem(m); + } + + /* + * Stick new segment in its place. + */ + insque_32(ti, (void *)(q->ti_prev)); + +present: + /* + * Present data to user, advancing rcv_nxt through + * completed sequence space. + */ + if (!TCPS_HAVEESTABLISHED(tp->t_state)) + return (0); + ti = (struct tcpiphdr *) tp->seg_next; + if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) + return (0); + if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) + return (0); + do { + tp->rcv_nxt += ti->ti_len; + flags = ti->ti_flags & TH_FIN; + remque_32(ti); + m = (struct SLIRPmbuf *) 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); + else { + if (so->so_emu) { + if (tcp_emu(so,m)) sbappend(so, m); + } else + sbappend(so, m); + } + } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); +/* sorwakeup(so); */ + return (flags); +} + +/* + * TCP input routine, follows pages 65-76 of the + * protocol specification dated September, 1981 very closely. + */ +void +tcp_input(m, iphlen, inso) + struct SLIRPmbuf *m; + int iphlen; + struct SLIRPsocket *inso; +{ + struct ip save_ip, *ip; + struct tcpiphdr *ti; + SLIRPcaddr_t optp = NULL; + int optlen = 0; + int len, tlen, off; + struct tcpcb *tp = 0; + int tiflags; + struct SLIRPsocket *so = 0; + int todrop, acked, ourfinisacked, needoutput = 0; +/* int dropsocket = 0; */ + int iss = 0; + u_long tiwin; + int ret; +/* int ts_present = 0; */ + + DEBUG_CALL("tcp_input"); + 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; + so->so_m = 0; + 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 SLIRPmbuf. + * Note: IP leaves IP header in first SLIRPmbuf. + */ + ti = mtod(m, struct tcpiphdr *); + if (iphlen > sizeof(struct ip )) { + ip_stripoptions(m, (struct SLIRPmbuf *)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; + save_ip.ip_len+= iphlen; + + /* + * Checksum extended TCP header and data. + */ + tlen = ((struct ip *)ti)->ip_len; + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_len = htons((u_int16_t)tlen); + len = sizeof(struct ip ) + tlen; + /* keep checksum for ICMP reply + * ti->ti_sum = cksum(m, len); + * if (ti->ti_sum) { */ + if(cksum(m, len)) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } + + /* + * Check that TCP offset makes sense, + * pull out TCP options and adjust length. XXX + */ + off = ti->ti_off << 2; + if (off < sizeof (struct tcphdr) || off > tlen) { + tcpstat.tcps_rcvbadoff++; + goto drop; + } + tlen -= off; + ti->ti_len = tlen; + if (off > sizeof (struct tcphdr)) { + optlen = off - sizeof (struct tcphdr); + optp = mtod(m, SLIRPcaddr_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 + * quickly get the values now and not bother calling + * tcp_dooptions(), etc. + */ +/* if ((optlen == TCPOLEN_TSTAMP_APPA || + * (optlen > TCPOLEN_TSTAMP_APPA && + * optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && + * *(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) && + * (ti->ti_flags & TH_SYN) == 0) { + * ts_present = 1; + * ts_val = ntohl(*(u_int32_t *)(optp + 4)); + * ts_ecr = ntohl(*(u_int32_t *)(optp + 8)); + * optp = NULL; / * we've parsed the options * / + * } + */ + } + tiflags = ti->ti_flags; + + /* + * Convert TCP protocol specific fields to host format. + */ + NTOHL(ti->ti_seq); + NTOHL(ti->ti_ack); + NTOHS(ti->ti_win); + NTOHS(ti->ti_urp); + + /* + * Drop TCP, IP headers and TCP options. + */ + m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + + /* + * Locate pcb for segment. + */ +findso: + so = tcp_last_so; + if (so->so_fport != ti->ti_dport || + so->so_lport != ti->ti_sport || + so->so_laddr.s_addr != ti->ti_src.s_addr || + so->so_faddr.s_addr != ti->ti_dst.s_addr) { + so = solookup(&tcb, ti->ti_src, ti->ti_sport, + ti->ti_dst, ti->ti_dport); + if (so) + tcp_last_so = so; + ++tcpstat.tcps_socachemiss; + } + + /* + * If the state is CLOSED (i.e., TCB does not exist) then + * all data in the incoming segment is discarded. + * If the TCB exists but is in CLOSED state, it is embryonic, + * 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... + * + * 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... + */ + 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); + + /* 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 + * or something else, we nuke it. + */ + if (so->so_state & SS_ISFCONNECTING) + 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; + * else + */ + tiwin = ti->ti_win; + + /* + * Segment received on connection. + * Reset idle time and keep-alive timer. + */ + tp->t_idle = 0; + if (so_options) + tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + else + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + + /* + * Process options if not in LISTEN state, + * else do it below (after getting remote address). + */ + if (optp && tp->t_state != TCPS_LISTEN) + 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 + * change and we're not retransmitting, it's a + * candidate. If the length is zero and the ack moved + * forward, we're the sender side of the xfer. Just + * free the data acked & wake any higher level process + * that was blocked waiting for space. If the length + * is non-zero and the ack didn't move, we're the + * receiver side. If we're getting packets in-order + * (the reassembly queue is empty), add the data to + * the socket buffer and note that we need a delayed ack. + * + * XXX Some of these tests are not needed + * eg: the tiwin == tp->snd_wnd prevents many more + * predictions.. with no *real* advantage.. + */ + if (tp->t_state == TCPS_ESTABLISHED && + (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && +/* (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) && */ + 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. + */ +/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && + * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { + * tp->ts_recent_age = tcp_now; + * tp->ts_recent = ts_val; + * } + */ + if (ti->ti_len == 0) { + if (SEQ_GT(ti->ti_ack, tp->snd_una) && + SEQ_LEQ(ti->ti_ack, tp->snd_max) && + tp->snd_cwnd >= tp->snd_wnd) { + /* + * this is a pure ack for outstanding data. + */ + ++tcpstat.tcps_predack; +/* 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); + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + sbdrop(&so->so_snd, acked); + tp->snd_una = ti->ti_ack; + m_freem(m); + + /* + * If all outstanding data are acked, stop + * retransmit timer, otherwise restart timer + * using current (possibly backed-off) value. + * If process is waiting for space, + * wakeup/selwakeup/signal. If data + * are ready to send, let tcp_output + * decide between more output or persist. + */ + if (tp->snd_una == tp->snd_max) + tp->t_timer[TCPT_REXMT] = 0; + 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??? + */ + if (so->so_snd.sb_cc) + (void) tcp_output(tp); + + return; + } + } else if (ti->ti_ack == tp->snd_una && + tp->seg_next == (tcpiphdrp_32)tp && + ti->ti_len <= sbspace(&so->so_rcv)) { + /* + * this is a pure, in-sequence data packet + * with nothing on the reassembly queue and + * we have enough buffer space to take it. + */ + ++tcpstat.tcps_preddat; + tp->rcv_nxt += ti->ti_len; + tcpstat.tcps_rcvpack++; + tcpstat.tcps_rcvbyte += ti->ti_len; + /* + * Add data to socket buffer. + */ + if (so->so_emu) { + if (tcp_emu(so,m)) sbappend(so, m); + } else + sbappend(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; + } + } /* header prediction */ + /* + * Calculate amount of space in receive window, + * and then do TCP input processing. + * Receive window is amount of space in rcv queue, + * but not less than advertised window. + */ + { int win; + win = sbspace(&so->so_rcv); + if (win < 0) + win = 0; + tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt)); + } + + switch (tp->t_state) { + + /* + * If the state is LISTEN then ignore segment if it contains an RST. + * If the segment contains an ACK then it is bad and send a RST. + * If it does not contain a SYN then it is not interesting; drop it. + * Don't bother responding if the destination was a broadcast. + * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial + * tp->iss, and send a segment: + * + * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. + * Fill in remote peer address fields if not previously specified. + * Enter SYN_RECEIVED state, and process any other fields of this + * segment in this state. + */ + case TCPS_LISTEN: { + + if (tiflags & TH_RST) + goto drop; + if (tiflags & TH_ACK) + 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", + errno,strerror(errno))); + 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); + } else { + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + HTONL(ti->ti_seq); /* restore tcp header */ + HTONL(ti->ti_ack); + HTONS(ti->ti_win); + HTONS(ti->ti_urp); + m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + m->m_len += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + *ip=save_ip; + icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno)); + } + tp = tcp_close(tp); + m_free(m); + } else { + /* + * Haven't connected yet, save the current SLIRPmbuf + * and ti, and return + * XXX Some OS's don't tell us whether the connect() + * succeeded or not. So we must time it out. + */ + so->so_m = m; + so->so_ti = ti; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->t_state = TCPS_SYN_RECEIVED; + } + return; + + cont_conn: + /* m==NULL + * Check if the connect succeeded + */ + if (so->so_state & SS_NOFDREF) { + tp = tcp_close(tp); + goto dropwithreset; + } + 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 + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tp->irs = ti->ti_seq; + tcp_sendseqinit(tp); + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + tp->t_state = TCPS_SYN_RECEIVED; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tcpstat.tcps_accepts++; + goto trimthenstep6; + } /* case TCPS_LISTEN */ + + /* + * If the state is SYN_SENT: + * if seg contains an ACK, but not for our SYN, drop the input. + * if seg contains a RST, then drop the connection. + * if seg does not contain SYN, then drop it. + * Otherwise this is an acceptable SYN segment + * initialize tp->rcv_nxt and tp->irs + * if seg contains ack then advance tp->snd_una + * if SYN has been acked change to ESTABLISHED else SYN_RCVD state + * arrange for segment to be acked (eventually) + * continue processing rest of data/controls, beginning with URG + */ + case TCPS_SYN_SENT: + if ((tiflags & TH_ACK) && + (SEQ_LEQ(ti->ti_ack, tp->iss) || + SEQ_GT(ti->ti_ack, tp->snd_max))) + goto dropwithreset; + + if (tiflags & TH_RST) { + if (tiflags & TH_ACK) + tp = tcp_drop(tp,0); /* XXX Check t_softerror! */ + goto drop; + } + + if ((tiflags & TH_SYN) == 0) + goto drop; + if (tiflags & TH_ACK) { + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + } + + tp->t_timer[TCPT_REXMT] = 0; + tp->irs = ti->ti_seq; + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { + 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)) { + * tp->snd_scale = tp->requested_s_scale; + * tp->rcv_scale = tp->request_r_scale; + * } + */ + (void) tcp_reass(tp, (struct tcpiphdr *)0, + (struct SLIRPmbuf *)0); + /* + * if we didn't have to retransmit the SYN, + * use its rtt as our initial srtt & rtt var. + */ + if (tp->t_rtt) + tcp_xmit_timer(tp, tp->t_rtt); + } else + tp->t_state = TCPS_SYN_RECEIVED; + +trimthenstep6: + /* + * Advance ti->ti_seq to correspond to first data byte. + * If data, trim to stay within window, + * dropping FIN if necessary. + */ + ti->ti_seq++; + if (ti->ti_len > tp->rcv_wnd) { + todrop = ti->ti_len - tp->rcv_wnd; + m_adj(m, -todrop); + ti->ti_len = tp->rcv_wnd; + tiflags &= ~TH_FIN; + tcpstat.tcps_rcvpackafterwin++; + tcpstat.tcps_rcvbyteafterwin += todrop; + } + tp->snd_wl1 = ti->ti_seq - 1; + tp->rcv_up = ti->ti_seq; + goto step6; + } /* switch tp->t_state */ + /* + * States other than LISTEN or SYN_SENT. + * First check timestamp, if present. + * 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. + */ +/* if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent && + * TSTMP_LT(ts_val, tp->ts_recent)) { + * + */ /* Check to see if ts_recent is over 24 days old. */ +/* if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { + */ /* + * * Invalidate ts_recent. If this segment updates + * * ts_recent, the age will be reset later and ts_recent + * * will get a valid value. If it does not, setting + * * ts_recent to zero will at least satisfy the + * * requirement that zero be placed in the timestamp + * * echo reply when ts_recent isn't valid. The + * * age isn't reset until we get a valid ts_recent + * * because we don't want out-of-order segments to be + * * dropped when ts_recent is old. + * */ +/* tp->ts_recent = 0; + * } else { + * tcpstat.tcps_rcvduppack++; + * tcpstat.tcps_rcvdupbyte += ti->ti_len; + * tcpstat.tcps_pawsdrop++; + * goto dropafterack; + * } + * } + */ + + todrop = tp->rcv_nxt - ti->ti_seq; + if (todrop > 0) { + if (tiflags & TH_SYN) { + tiflags &= ~TH_SYN; + ti->ti_seq++; + if (ti->ti_urp > 1) + ti->ti_urp--; + else + tiflags &= ~TH_URG; + todrop--; + } + /* + * Following if statement from Stevens, vol. 2, p. 960. + */ + if (todrop > ti->ti_len + || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { + /* + * Any valid FIN must be to the left of the window. + * At this point the FIN must be a duplicate or out + * of sequence; drop it. + */ + tiflags &= ~TH_FIN; + + /* + * Send an ACK to resynchronize and drop any data. + * But keep on processing for RST or ACK. + */ + tp->t_flags |= TF_ACKNOW; + todrop = ti->ti_len; + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += todrop; + } else { + tcpstat.tcps_rcvpartduppack++; + tcpstat.tcps_rcvpartdupbyte += todrop; + } + m_adj(m, todrop); + ti->ti_seq += todrop; + ti->ti_len -= todrop; + if (ti->ti_urp > todrop) + ti->ti_urp -= todrop; + else { + tiflags &= ~TH_URG; + ti->ti_urp = 0; + } + } + /* + * If new data are received on a connection after the + * user processes are gone, then RST the other end. + */ + if ((so->so_state & SS_NOFDREF) && + tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { + tp = tcp_close(tp); + tcpstat.tcps_rcvafterclose++; + goto dropwithreset; + } + + /* + * If segment ends after window, drop trailing data + * (and PUSH and FIN); if nothing left, just ACK. + */ + todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); + if (todrop > 0) { + tcpstat.tcps_rcvpackafterwin++; + if (todrop >= ti->ti_len) { + tcpstat.tcps_rcvbyteafterwin += ti->ti_len; + /* + * If a new connection request is received + * while in TIME_WAIT, drop the old connection + * and start over if the sequence numbers + * are above the previous ones. + */ + if (tiflags & TH_SYN && + tp->t_state == TCPS_TIME_WAIT && + SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { + iss = tp->rcv_nxt + TCP_ISSINCR; + tp = tcp_close(tp); + goto findso; + } + /* + * If window is closed can only take segments at + * window edge, and have to drop data and PUSH from + * incoming segments. Continue processing, but + * remember to ack. Otherwise, drop segment + * and ack. + */ + if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_rcvwinprobe++; + } else + goto dropafterack; + } else + tcpstat.tcps_rcvbyteafterwin += todrop; + m_adj(m, -todrop); + ti->ti_len -= todrop; + tiflags &= ~(TH_PUSH|TH_FIN); + } + + /* + * If last ACK falls within this segment's sequence numbers, + * record its timestamp. + */ +/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && + * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len + + * ((tiflags & (TH_SYN|TH_FIN)) != 0))) { + * tp->ts_recent_age = tcp_now; + * tp->ts_recent = ts_val; + * } + */ + + /* + * If the RST bit is set examine the state: + * SYN_RECEIVED STATE: + * If passive open, return to LISTEN state. + * If active open, inform user that connection was refused. + * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: + * Inform user that connection was reset, and close tcb. + * CLOSING, LAST_ACK, TIME_WAIT STATES + * Close the tcb. + */ + if (tiflags&TH_RST) switch (tp->t_state) { + + case TCPS_SYN_RECEIVED: +/* so->so_error = ECONNREFUSED; */ + goto close; + + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: +/* so->so_error = ECONNRESET; */ + close: + tp->t_state = TCPS_CLOSED; + tcpstat.tcps_drops++; + tp = tcp_close(tp); + goto drop; + + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + tp = tcp_close(tp); + goto drop; + } + + /* + * If a SYN is in the window, then this is an + * error and we send an RST and drop the connection. + */ + if (tiflags & TH_SYN) { + tp = tcp_drop(tp,0); + goto dropwithreset; + } + + /* + * If the ACK bit is off we drop the segment and return. + */ + if ((tiflags & TH_ACK) == 0) goto drop; + + /* + * Ack processing. + */ + switch (tp->t_state) { + /* + * In SYN_RECEIVED state if the ack ACKs our SYN then enter + * ESTABLISHED state and continue processing, otherwise + * send an RST. una<=ack<=max + */ + case TCPS_SYN_RECEIVED: + + if (SEQ_GT(tp->snd_una, ti->ti_ack) || + SEQ_GT(ti->ti_ack, tp->snd_max)) + 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 + * 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=ti->ti_ack; + if (so->so_state & SS_CTL) { + /* So tcp_ctl reports the right state */ + ret = tcp_ctl(so); + if (ret == 1) { + soisfconnected(so); + so->so_state &= ~SS_CTL; /* success XXX */ + } else if (ret == 2) { + so->so_state = SS_NOFDREF; /* CTL_CMD */ + } else { + needoutput = 1; + tp->t_state = TCPS_FIN_WAIT_1; + } + } else { + soisfconnected(so); + } + + /* Do window scaling? */ +/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + * (TF_RCVD_SCALE|TF_REQ_SCALE)) { + * tp->snd_scale = tp->requested_s_scale; + * tp->rcv_scale = tp->request_r_scale; + * } + */ + (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct SLIRPmbuf *)0); + tp->snd_wl1 = ti->ti_seq - 1; + /* Avoid ack processing; snd_una==ti_ack => dup ack */ + goto synrx_to_est; + /* fall into ... */ + + /* + * In ESTABLISHED state: drop duplicate ACKs; ACK out of range + * ACKs. If the ack is in the range + * tp->snd_una < ti->ti_ack <= tp->snd_max + * then advance tp->snd_una to ti->ti_ack and drop + * data from the retransmission queue. If this ACK reflects + * more up to date window information we update our window information. + */ + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + + if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { + if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { + tcpstat.tcps_rcvdupack++; + DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n", + (long )m, (long )so)); + /* + * If we have outstanding data (other than + * a window probe), this is a completely + * duplicate ack (ie, window info didn't + * change), the ack is the biggest we've + * seen and we've seen exactly our rexmt + * threshold of them, assume a packet + * has been dropped and retransmit it. + * Kludge snd_nxt & the congestion + * window so we send only this one + * packet. + * + * We know we're losing at the current + * window size so do congestion avoidance + * (set ssthresh to half the current window + * and pull our congestion window back to + * the new ssthresh). + * + * Dup acks mean that packets have left the + * 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. + */ + if (tp->t_timer[TCPT_REXMT] == 0 || + ti->ti_ack != tp->snd_una) + tp->t_dupacks = 0; + else if (++tp->t_dupacks == tcprexmtthresh) { + tcp_seq onxt = tp->snd_nxt; + u_int win = + min(tp->snd_wnd, tp->snd_cwnd) / 2 / + tp->t_maxseg; + + if (win < 2) + win = 2; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_timer[TCPT_REXMT] = 0; + tp->t_rtt = 0; + tp->snd_nxt = ti->ti_ack; + tp->snd_cwnd = tp->t_maxseg; + (void) tcp_output(tp); + tp->snd_cwnd = tp->snd_ssthresh + + tp->t_maxseg * tp->t_dupacks; + if (SEQ_GT(onxt, tp->snd_nxt)) + tp->snd_nxt = onxt; + goto drop; + } else if (tp->t_dupacks > tcprexmtthresh) { + tp->snd_cwnd += tp->t_maxseg; + (void) tcp_output(tp); + goto drop; + } + } else + tp->t_dupacks = 0; + break; + } + synrx_to_est: + /* + * If the congestion window was inflated to account + * for the other side's cached packets, retract it. + */ + if (tp->t_dupacks > tcprexmtthresh && + tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd = tp->snd_ssthresh; + tp->t_dupacks = 0; + if (SEQ_GT(ti->ti_ack, tp->snd_max)) { + tcpstat.tcps_rcvacktoomuch++; + goto dropafterack; + } + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + + /* + * If we have a timestamp reply, update smoothed + * round trip time. If no timestamp is present but + * transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + * Since we now have an rtt measurement, cancel the + * timer backoff (cf., Phil Karn's retransmit alg.). + * Recompute the initial retransmit timer. + */ +/* 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); + + /* + * If all outstanding data is acked, stop retransmit + * timer and remember to restart (more output or persist). + * If there is more data to be acked, restart retransmit + * timer, using current (possibly backed-off) value. + */ + if (ti->ti_ack == tp->snd_max) { + tp->t_timer[TCPT_REXMT] = 0; + needoutput = 1; + } else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * When new data is acked, open the congestion window. + * If the window gives us less than ssthresh packets + * in flight, open exponentially (maxseg per packet). + * Otherwise open linearly: maxseg per window + * (maxseg^2 / cwnd per packet). + */ + { + u_int cw = tp->snd_cwnd; + u_int incr = tp->t_maxseg; + + if (cw > tp->snd_ssthresh) + incr = incr * incr / cw; + tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); + } + 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); + ourfinisacked = 1; + } else { + sbdrop(&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 + */ +/* if (so->so_snd.sb_flags & SB_NOTIFY) + * sowwakeup(so); + */ + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + + switch (tp->t_state) { + + /* + * In FIN_WAIT_1 STATE in addition to the processing + * for the ESTABLISHED state if our FIN is now acknowledged + * then enter FIN_WAIT_2. + */ + case TCPS_FIN_WAIT_1: + if (ourfinisacked) { + /* + * If we can't receive any more + * data, then closing user can proceed. + * Starting the timer is contrary to the + * specification, but if we don't get a FIN + * we'll hang forever. + */ + if (so->so_state & SS_FCANTRCVMORE) { + soisfdisconnected(so); + tp->t_timer[TCPT_2MSL] = tcp_maxidle; + } + tp->t_state = TCPS_FIN_WAIT_2; + } + break; + + /* + * In CLOSING STATE in addition to the processing for + * the ESTABLISHED state if the ACK acknowledges our FIN + * then enter the TIME-WAIT state, otherwise ignore + * the segment. + */ + case TCPS_CLOSING: + if (ourfinisacked) { + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisfdisconnected(so); + } + break; + + /* + * In LAST_ACK, we may still be waiting for data to drain + * and/or to be acked, as well as for the ack of our FIN. + * If our FIN is now acknowledged, delete the TCB, + * enter the closed state and return. + */ + case TCPS_LAST_ACK: + if (ourfinisacked) { + tp = tcp_close(tp); + goto drop; + } + break; + + /* + * In TIME_WAIT state the only thing that should arrive + * is a retransmission of the remote FIN. Acknowledge + * it and restart the finack timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + goto dropafterack; + } + } /* switch(tp->t_state) */ + +step6: + /* + * Update window information. + * 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) || + (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 */ + if (ti->ti_len == 0 && + tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) + tcpstat.tcps_rcvwinupd++; + tp->snd_wnd = tiwin; + tp->snd_wl1 = ti->ti_seq; + tp->snd_wl2 = ti->ti_ack; + if (tp->snd_wnd > tp->max_sndwnd) + tp->max_sndwnd = tp->snd_wnd; + needoutput = 1; + } + + /* + * Process segments with URG. + */ + if ((tiflags & TH_URG) && ti->ti_urp && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * This is a kludge, but if we receive and accept + * random urgent pointers, we'll crash in + * soreceive. It's hard to imagine someone + * actually wanting to send this much urgent data. + */ + if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) { + ti->ti_urp = 0; + tiflags &= ~TH_URG; + goto dodata; + } + /* + * 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. + * 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 + * spec states (in one of two places). + */ + if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { + tp->rcv_up = ti->ti_seq + ti->ti_urp; + 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 + /* + * If no out of band data is expected, + * pull receive urgent pointer along + * with the receive window. + */ + if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) + tp->rcv_up = tp->rcv_nxt; +dodata: + + /* + * Process the segment text, merging it into the TCP sequencing queue, + * and arranging for acknowledgment of receipt if necessary. + * This process logically involves adjusting tp->rcv_wnd as data + * is presented to the user (this happens in tcp_usrreq.c, + * case PRU_RCVD). If a FIN has already been received on this + * connection then we just ignore the text. + */ + if ((ti->ti_len || (tiflags&TH_FIN)) && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + TCP_REASS(tp, ti, m, so, tiflags); + /* + * Note the amount of data that peer has sent into + * our window, in order to estimate the sender's + * buffer size. + */ + len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt); + } else { + m_free(m); + tiflags &= ~TH_FIN; + } + + /* + * If FIN is received ACK the FIN and let the user know + * that the connection is closing. + */ + if (tiflags & TH_FIN) { + if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * If we receive a FIN we can't send more data, + * set it SS_FDRAIN + * Shutdown the socket if there is no rx data in the + * buffer. + * soread() is called on completion of shutdown() and + * will got to TCPS_LAST_ACK, and use tcp_output() + * to send the FIN. + */ +/* sofcantrcvmore(so); */ + sofwdrain(so); + + tp->t_flags |= TF_ACKNOW; + tp->rcv_nxt++; + } + switch (tp->t_state) { + + /* + * In SYN_RECEIVED and ESTABLISHED STATES + * enter the CLOSE_WAIT state. + */ + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + if(so->so_emu == EMU_CTL) /* no shutdown on socket */ + tp->t_state = TCPS_LAST_ACK; + else + tp->t_state = TCPS_CLOSE_WAIT; + break; + + /* + * If still in FIN_WAIT_1 STATE FIN has not been acked so + * enter the CLOSING state. + */ + case TCPS_FIN_WAIT_1: + tp->t_state = TCPS_CLOSING; + break; + + /* + * In FIN_WAIT_2 state enter the TIME_WAIT state, + * starting the time-wait timer, turning off the other + * standard timers. + */ + case TCPS_FIN_WAIT_2: + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisfdisconnected(so); + break; + + /* + * In TIME_WAIT state restart the 2 MSL time_wait timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + break; + } + } + + /* + * 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) { + */ +/* if ((ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg && + * (so->so_iptos & IPTOS_LOWDELAY) == 0) || + * ((so->so_iptos & IPTOS_LOWDELAY) && + * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { + */ + if (ti->ti_len && (unsigned)ti->ti_len <= 5 && + ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { + tp->t_flags |= TF_ACKNOW; + } + + /* + * Return any desired output. + */ + if (needoutput || (tp->t_flags & TF_ACKNOW)) { + (void) tcp_output(tp); + } + return; + +dropafterack: + /* + * Generate an ACK dropping incoming segment if it occupies + * sequence space, where the ACK reflects our state. + */ + if (tiflags & TH_RST) + goto drop; + m_freem(m); + tp->t_flags |= TF_ACKNOW; + (void) tcp_output(tp); + return; + +dropwithreset: + /* reuses m if m!=NULL, m_free() unnecessary */ + if (tiflags & TH_ACK) + tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); + else { + if (tiflags & TH_SYN) ti->ti_len++; + tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, + TH_RST|TH_ACK); + } + + return; + +drop: + /* + * Drop space held by incoming segment and return. + */ + m_free(m); + + return; +} + + /* , ts_present, ts_val, ts_ecr) */ +/* int *ts_present; + * u_int32_t *ts_val, *ts_ecr; + */ +void +tcp_dooptions(tp, cp, cnt, ti) + struct tcpcb *tp; + u_char *cp; + int cnt; + struct tcpiphdr *ti; +{ + u_int16_t mss; + int opt, optlen; + + DEBUG_CALL("tcp_dooptions"); + DEBUG_ARGS((dfd," tp = %lx cnt=%i \n", (long )tp, cnt)); + + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[0]; + if (opt == TCPOPT_EOL) + break; + if (opt == TCPOPT_NOP) + optlen = 1; + else { + optlen = cp[1]; + if (optlen <= 0) + break; + } + switch (opt) { + + default: + continue; + + case TCPOPT_MAXSEG: + if (optlen != TCPOLEN_MAXSEG) + continue; + if (!(ti->ti_flags & TH_SYN)) + continue; + memcpy((char *) &mss, (char *) cp + 2, sizeof(mss)); + NTOHS(mss); + (void) tcp_mss(tp, mss); /* sets t_maxseg */ + break; + +/* case TCPOPT_WINDOW: + * if (optlen != TCPOLEN_WINDOW) + * continue; + * if (!(ti->ti_flags & TH_SYN)) + * continue; + * tp->t_flags |= TF_RCVD_SCALE; + * tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); + * break; + */ +/* case TCPOPT_TIMESTAMP: + * if (optlen != TCPOLEN_TIMESTAMP) + * continue; + * *ts_present = 1; + * memcpy((char *) ts_val, (char *)cp + 2, sizeof(*ts_val)); + * NTOHL(*ts_val); + * 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. + * */ +/* if (ti->ti_flags & TH_SYN) { + * tp->t_flags |= TF_RCVD_TSTMP; + * tp->ts_recent = *ts_val; + * tp->ts_recent_age = tcp_now; + * } + */ break; + } + } +} + + +/* + * Pull out of band byte out of a segment so + * it doesn't appear in the user's data queue. + * It is still reflected in the segment length for + * sequencing purposes. + */ + +#ifdef notdef + +void +tcp_pulloutofband(so, ti, m) + struct SLIRPsocket *so; + struct tcpiphdr *ti; + struct SLIRPmbuf *m; +{ + int cnt = ti->ti_urp - 1; + + while (cnt >= 0) { + if (m->m_len > cnt) { + char *cp = mtod(m, SLIRPcaddr_t) + cnt; + struct tcpcb *tp = sototcpcb(so); + + tp->t_iobc = *cp; + tp->t_oobflags |= TCPOOB_HAVEDATA; + memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1)); + m->m_len--; + return; + } + cnt -= m->m_len; + m = m->m_next; /* XXX WRONG! Fix it! */ + if (m == 0) + break; + } + panic("tcp_pulloutofband"); +} + +#endif /* notdef */ + +/* + * Collect new round-trip time estimate + * and update averages and current timeout. + */ + +void +tcp_xmit_timer(tp, rtt) + struct tcpcb *tp; + int rtt; +{ + short delta; + + DEBUG_CALL("tcp_xmit_timer"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("rtt = %d", rtt); + + tcpstat.tcps_rttupdated++; + if (tp->t_srtt != 0) { + /* + * srtt is stored as fixed point with 3 bits after the + * binary point (i.e., scaled by 8). The following magic + * is equivalent to the smoothing algorithm in rfc793 with + * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed + * point). Adjust rtt to origin 0. + */ + delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT); + if ((tp->t_srtt += delta) <= 0) + tp->t_srtt = 1; + /* + * We accumulate a smoothed rtt variance (actually, a + * smoothed mean difference), then set the retransmit + * timer to smoothed rtt + 4 times the smoothed variance. + * rttvar is stored as fixed point with 2 bits after the + * binary point (scaled by 4). The following is + * equivalent to rfc793 smoothing with an alpha of .75 + * (rttvar = rttvar*3/4 + |delta| / 4). This replaces + * rfc793's wired-in beta. + */ + if (delta < 0) + delta = -delta; + delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT); + 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). + */ + tp->t_srtt = rtt << TCP_RTT_SHIFT; + tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); + } + tp->t_rtt = 0; + tp->t_rxtshift = 0; + + /* + * the retransmit should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + */ + 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 + * received recently. This isn't quite right, but close enough + * for now (a route might have failed after we sent a segment, + * and the return path might not be symmetrical). + */ + tp->t_softerror = 0; +} + +/* + * Determine a reasonable value for maxseg size. + * If the route is known, check route for mtu. + * If none, use an mss that can be handled on the outgoing + * interface without forcing IP to fragment; if bigger than + * an SLIRPmbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES + * to utilize large SLIRPmbufs. If no route is found, route has no mtu, + * or the destination isn't local, use a default, hopefully conservative + * size (usually 512 or the default IP max size, but no more than the mtu + * of the interface), as we can't discover anything about intervening + * gateways or networks. We also initialize the congestion/slow start + * window to be a single segment if the destination isn't local. + * While looking at the routing entry, we also initialize other path-dependent + * parameters from pre-set or cached values in the routing entry. + */ + +int +tcp_mss(tp, offer) + struct tcpcb *tp; + u_int offer; +{ + struct SLIRPsocket *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)); + + DEBUG_MISC((dfd, " returning mss = %d\n", mss)); + + return mss; +} diff --git a/src/slirp/tcp_output.c b/src/slirp/tcp_output.c new file mode 100644 index 000000000..7d75b64b2 --- /dev/null +++ b/src/slirp/tcp_output.c @@ -0,0 +1,601 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93 + * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +/* + * Since this is only used in "stats socket", we give meaning + * names instead of the REAL names + */ +char *tcpstates[] = { +/* "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", */ + "REDIRECT", "LISTEN", "SYN_SENT", "SYN_RCVD", + "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", + "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", +}; + +u_char tcp_outflags[TCP_NSTATES] = { + TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, + TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, + TH_FIN|TH_ACK, TH_ACK, TH_ACK, +}; + + +#define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ + +/* + * Tcp output routine: figure out what should be sent and send it. + */ +int +tcp_output(tp) + struct tcpcb *tp; +{ + struct SLIRPsocket *so = tp->t_socket; + register long len, win; + int off, flags, error; + struct SLIRPmbuf *m; + struct tcpiphdr *ti; + u_char opt[MAX_TCPOPTLEN]; + unsigned optlen, hdrlen; + int idle, sendalot; + + DEBUG_CALL("tcp_output"); + DEBUG_ARG("tp = %lx", (long )tp); + + /* + * Determine length of data that should be transmitted, + * and flags that will be used. + * If there is some data or critical controls (SYN, RST) + * to send, then transmit; otherwise, investigate further. + */ + idle = (tp->snd_max == tp->snd_una); + if (idle && tp->t_idle >= tp->t_rxtcur) + /* + * We have been idle for "a while" and no acks are + * expected to clock out any data we send -- + * slow start to get ack "clock" running again. + */ + tp->snd_cwnd = tp->t_maxseg; +again: + sendalot = 0; + off = tp->snd_nxt - tp->snd_una; + win = min(tp->snd_wnd, tp->snd_cwnd); + + flags = tcp_outflags[tp->t_state]; + + DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags)); + + /* + * If in persist timeout with window of 0, send 1 byte. + * Otherwise, if window is small but nonzero + * and timer expired, we will send what we can + * and go to transmit state. + */ + if (tp->t_force) { + if (win == 0) { + /* + * If we still have some data to send, then + * clear the FIN bit. Usually this would + * happen below when it realizes that we + * aren't sending all the data. However, + * if we have exactly 1 byte of unset data, + * then it won't clear the FIN bit below, + * and if we are in persist state, we wind + * up sending the packet without recording + * that we sent the FIN bit. + * + * We can't just blindly clear the FIN bit, + * because if we don't have any more data + * to send then the probe will be the FIN + * itself. + */ + if (off < so->so_snd.sb_cc) + flags &= ~TH_FIN; + win = 1; + } else { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + + len = min(so->so_snd.sb_cc, win) - off; + + if (len < 0) { + /* + * If FIN has been sent but not acked, + * but we haven't been called to retransmit, + * len will be -1. Otherwise, window shrank + * after we sent into it. If window shrank to 0, + * cancel pending retransmit and pull snd_nxt + * back to (closed) window. We will enter persist + * state below. If the window didn't close completely, + * just wait for an ACK. + */ + len = 0; + if (win == 0) { + tp->t_timer[TCPT_REXMT] = 0; + tp->snd_nxt = tp->snd_una; + } + } + + if (len > tp->t_maxseg) { + len = tp->t_maxseg; + sendalot = 1; + } + if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) + flags &= ~TH_FIN; + + win = sbspace(&so->so_rcv); + + /* + * Sender silly window avoidance. If connection is idle + * and can send all data, a maximum segment, + * at least a maximum default-size segment do it, + * or are forced, do it; otherwise don't bother. + * If peer's buffer is tiny, then send + * when window is at least half open. + * If retransmitting (possibly after persist timer forced us + * to send into a small window), then must resend. + */ + if (len) { + if (len == tp->t_maxseg) + goto send; + if ((1 || idle || tp->t_flags & TF_NODELAY) && + len + off >= so->so_snd.sb_cc) + goto send; + if (tp->t_force) + goto send; + if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) + goto send; + if (SEQ_LT(tp->snd_nxt, tp->snd_max)) + goto send; + } + + /* + * Compare available window to amount of window + * known to peer (as advertised window less + * next expected input). If the difference is at least two + * max size segments, or at least 50% of the maximum possible + * window, then want to send a window update to peer. + */ + if (win > 0) { + /* + * "adv" is the amount we can increase the window, + * taking into account that we are limited by + * TCP_MAXWIN << tp->rcv_scale. + */ + long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - + (tp->rcv_adv - tp->rcv_nxt); + + if (adv >= (long) (2 * tp->t_maxseg)) + goto send; + if (2 * adv >= (long) so->so_rcv.sb_datalen) + goto send; + } + + /* + * Send if we owe peer an ACK. + */ + if (tp->t_flags & TF_ACKNOW) + goto send; + if (flags & (TH_SYN|TH_RST)) + goto send; + if (SEQ_GT(tp->snd_up, tp->snd_una)) + goto send; + /* + * If our state indicates that FIN should be sent + * and we have not yet done so, or we're retransmitting the FIN, + * then we need to send. + */ + if (flags & TH_FIN && + ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) + goto send; + + /* + * TCP window updates are not reliable, rather a polling protocol + * using ``persist'' packets is used to insure receipt of window + * updates. The three ``states'' for the output side are: + * idle not doing retransmits or persists + * persisting to move a small or zero window + * (re)transmitting and thereby not persisting + * + * tp->t_timer[TCPT_PERSIST] + * is set when we are in persist state. + * tp->t_force + * is set when we are called to send a persist packet. + * tp->t_timer[TCPT_REXMT] + * is set when we are retransmitting + * The output side is idle when both timers are zero. + * + * If send window is too small, there is data to transmit, and no + * retransmit or persist is pending, then go to persist state. + * If nothing happens soon, send when timer expires: + * if window is nonzero, transmit what we can, + * otherwise force out a byte. + */ + if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && + tp->t_timer[TCPT_PERSIST] == 0) { + tp->t_rxtshift = 0; + tcp_setpersist(tp); + } + + /* + * No reason to send a segment, just return. + */ + tcpstat.tcps_didnuttin++; + + return (0); + +send: + /* + * Before ESTABLISHED, force sending of initial options + * unless TCP set not to do any options. + * NOTE: we assume that the IP/TCP header plus TCP options + * always fit in a single SLIRPmbuf, leaving room for a maximum + * link header, i.e. + * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN + */ + optlen = 0; + hdrlen = sizeof (struct tcpiphdr); + if (flags & TH_SYN) { + tp->snd_nxt = tp->iss; + if ((tp->t_flags & TF_NOOPT) == 0) { + u_int16_t mss; + + opt[0] = TCPOPT_MAXSEG; + opt[1] = 4; + mss = htons((u_int16_t) tcp_mss(tp, 0)); + memcpy((SLIRPcaddr_t)(opt + 2), (SLIRPcaddr_t)&mss, sizeof(mss)); + optlen = 4; + +/* if ((tp->t_flags & TF_REQ_SCALE) && + * ((flags & TH_ACK) == 0 || + * (tp->t_flags & TF_RCVD_SCALE))) { + * *((u_int32_t *) (opt + optlen)) = htonl( + * TCPOPT_NOP << 24 | + * TCPOPT_WINDOW << 16 | + * TCPOLEN_WINDOW << 8 | + * tp->request_r_scale); + * optlen += 4; + * } + */ + } + } + + /* + * Send a timestamp and echo-reply if this is a SYN and our side + * wants to use timestamps (TF_REQ_TSTMP is set) or both our side + * and our peer have sent timestamps in our SYN's. + */ +/* if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && + * (flags & TH_RST) == 0 && + * ((flags & (TH_SYN|TH_ACK)) == TH_SYN || + * (tp->t_flags & TF_RCVD_TSTMP))) { + * u_int32_t *lp = (u_int32_t *)(opt + optlen); + * + * / * Form timestamp option as shown in appendix A of RFC 1323. * / + * *lp++ = htonl(TCPOPT_TSTAMP_HDR); + * *lp++ = htonl(tcp_now); + * *lp = htonl(tp->ts_recent); + * optlen += TCPOLEN_TSTAMP_APPA; + * } + */ + hdrlen += optlen; + + /* + * Adjust data length if insertion of options will + * bump the packet length beyond the t_maxseg length. + */ + if (len > tp->t_maxseg - optlen) { + len = tp->t_maxseg - optlen; + sendalot = 1; + } + + /* + * Grab a header SLIRPmbuf, attaching a copy of data to + * be transmitted, and initialize the header from + * the template for sends on this connection. + */ + if (len) { + if (tp->t_force && len == 1) + tcpstat.tcps_sndprobe++; + else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { + tcpstat.tcps_sndrexmitpack++; + tcpstat.tcps_sndrexmitbyte += len; + } else { + tcpstat.tcps_sndpack++; + tcpstat.tcps_sndbyte += len; + } + + m = m_get(); + if (m == NULL) { +/* error = ENOBUFS; */ + error = 1; + goto out; + } + m->m_data += if_maxlinkhdr; + m->m_len = hdrlen; + + /* + * This will always succeed, since we make sure our SLIRPmbufs + * are big enough to hold one MSS packet + header + ... etc. + */ +/* if (len <= MHLEN - hdrlen - max_linkhdr) { */ + + sbcopy(&so->so_snd, off, (int) len, mtod(m, SLIRPcaddr_t) + hdrlen); + m->m_len += len; + +/* } else { + * m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len); + * if (m->m_next == 0) + * len = 0; + * } + */ + /* + * If we're sending everything we've got, set PUSH. + * (This will keep happy those implementations which only + * give data to the user when a buffer fills or + * a PUSH comes in.) + */ + if (off + len == so->so_snd.sb_cc) + flags |= TH_PUSH; + } else { + if (tp->t_flags & TF_ACKNOW) + tcpstat.tcps_sndacks++; + else if (flags & (TH_SYN|TH_FIN|TH_RST)) + tcpstat.tcps_sndctrl++; + else if (SEQ_GT(tp->snd_up, tp->snd_una)) + tcpstat.tcps_sndurg++; + else + tcpstat.tcps_sndwinup++; + + m = m_get(); + if (m == NULL) { +/* error = ENOBUFS; */ + error = 1; + goto out; + } + m->m_data += if_maxlinkhdr; + m->m_len = hdrlen; + } + + ti = mtod(m, struct tcpiphdr *); + + memcpy((SLIRPcaddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr)); + + /* + * Fill in fields, remembering maximum advertised + * window for use in delaying messages about window sizes. + * If resending a FIN, be sure not to use a new sequence number. + */ + if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && + tp->snd_nxt == tp->snd_max) + tp->snd_nxt--; + /* + * If we are doing retransmissions, then snd_nxt will + * not reflect the first unsent octet. For ACK only + * packets, we do not want the sequence number of the + * retransmitted packet, we want the sequence number + * of the next unsent octet. So, if there is no data + * (and no SYN or FIN), use snd_max instead of snd_nxt + * when filling in ti_seq. But if we are in persist + * state, snd_max might reflect one byte beyond the + * right edge of the window, so use snd_nxt in that + * case, since we know we aren't doing a retransmission. + * (retransmit and persist are mutually exclusive...) + */ + if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST]) + ti->ti_seq = htonl(tp->snd_nxt); + else + ti->ti_seq = htonl(tp->snd_max); + ti->ti_ack = htonl(tp->rcv_nxt); + if (optlen) { + memcpy((SLIRPcaddr_t)(ti + 1), (SLIRPcaddr_t)opt, optlen); + ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; + } + ti->ti_flags = flags; + /* + * Calculate receive window. Don't shrink window, + * but avoid silly window syndrome. + */ + if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg) + win = 0; + if (win > (long)TCP_MAXWIN << tp->rcv_scale) + win = (long)TCP_MAXWIN << tp->rcv_scale; + if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) + win = (long)(tp->rcv_adv - tp->rcv_nxt); + ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale)); + + if (SEQ_GT(tp->snd_up, tp->snd_una)) { + ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); +#ifdef notdef + if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { + ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); +#endif + ti->ti_flags |= TH_URG; + } else + /* + * If no urgent pointer to send, then we pull + * the urgent pointer to the left edge of the send window + * so that it doesn't drift into the send window on sequence + * number wraparound. + */ + tp->snd_up = tp->snd_una; /* drag it along */ + + /* + * Put TCP length in extended header, and then + * checksum extended header and data. + */ + if (len + optlen) + ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + + optlen + len)); + ti->ti_sum = cksum(m, (int)(hdrlen + len)); + + /* + * In transmit state, time the transmission and arrange for + * the retransmit. In persist state, just set snd_max. + */ + if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { + tcp_seq startseq = tp->snd_nxt; + + /* + * Advance snd_nxt over sequence space of this segment. + */ + if (flags & (TH_SYN|TH_FIN)) { + if (flags & TH_SYN) + tp->snd_nxt++; + if (flags & TH_FIN) { + tp->snd_nxt++; + tp->t_flags |= TF_SENTFIN; + } + } + tp->snd_nxt += len; + if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { + tp->snd_max = tp->snd_nxt; + /* + * Time this transmission if not a retransmission and + * not currently timing anything. + */ + if (tp->t_rtt == 0) { + tp->t_rtt = 1; + tp->t_rtseq = startseq; + tcpstat.tcps_segstimed++; + } + } + + /* + * Set retransmit timer if not currently set, + * and not doing an ack or a keep-alive probe. + * Initial value for retransmit timer is smoothed + * round-trip time + 2 * round-trip time variance. + * Initialize shift counter which is used for backoff + * of retransmit time. + */ + if (tp->t_timer[TCPT_REXMT] == 0 && + tp->snd_nxt != tp->snd_una) { + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + if (tp->t_timer[TCPT_PERSIST]) { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + } else + if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) + tp->snd_max = tp->snd_nxt + len; + + /* + * Fill in IP length and desired time to live and + * send to IP level. There should be a better way + * to handle ttl and tos; we could keep them in + * the template, but need a way to checksum without them. + */ + m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ + + { + + ((struct ip *)ti)->ip_len = m->m_len; + + ((struct ip *)ti)->ip_ttl = ip_defttl; + ((struct ip *)ti)->ip_tos = so->so_iptos; + +/* #if BSD >= 43 */ + /* Don't do IP options... */ +/* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, + * so->so_options & SO_DONTROUTE, 0); + */ + error = ip_output(so, m); + +/* #else + * error = ip_output(m, (struct SLIRPmbuf *)0, &tp->t_inpcb->inp_route, + * so->so_options & SO_DONTROUTE); + * #endif + */ + } + if (error) { +out: +/* if (error == ENOBUFS) { + * tcp_quench(tp->t_inpcb, 0); + * return (0); + * } + */ +/* if ((error == EHOSTUNREACH || error == ENETDOWN) + * && TCPS_HAVERCVDSYN(tp->t_state)) { + * tp->t_softerror = error; + * return (0); + * } + */ + return (error); + } + tcpstat.tcps_sndtotal++; + + /* + * Data sent (as far as we can tell). + * If this advertises a larger window than any other segment, + * then remember the size of the advertised window. + * Any pending ACK has now been sent. + */ + if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) + tp->rcv_adv = tp->rcv_nxt + win; + tp->last_ack_sent = tp->rcv_nxt; + tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); + if (sendalot) + goto again; + + return (0); +} + +void +tcp_setpersist(tp) + struct tcpcb *tp; +{ + int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; + +/* if (tp->t_timer[TCPT_REXMT]) + * panic("tcp_output REXMT"); + */ + /* + * Start/restart persistence timer. + */ + TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], + t * tcp_backoff[tp->t_rxtshift], + TCPTV_PERSMIN, TCPTV_PERSMAX); + if (tp->t_rxtshift < TCP_MAXRXTSHIFT) + tp->t_rxtshift++; +} diff --git a/src/slirp/tcp_subr.c b/src/slirp/tcp_subr.c new file mode 100644 index 000000000..cb0f0750a --- /dev/null +++ b/src/slirp/tcp_subr.c @@ -0,0 +1,1324 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93 + * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#include "slirp.h" + +/* patchable/settable parameters for tcp */ +int tcp_mssdflt = TCP_MSS; +int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; +int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */ +int tcp_rcvspace; /* You may want to change this */ +int tcp_sndspace; /* Keep small if you have an error prone link */ + +/* + * Tcp initialization + */ +void +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)); +} + +/* + * Create template to be used to send tcp packets on a connection. + * Call after host entry created, fills + * in a skeletal tcp/ip header, minimizing the amount of work + * necessary when the connection is used. + */ +/* struct tcpiphdr * */ +void +tcp_template(tp) + struct tcpcb *tp; +{ + struct SLIRPsocket *so = tp->t_socket; + struct tcpiphdr *n = &tp->t_template; + + n->ti_next = n->ti_prev = 0; + n->ti_x1 = 0; + n->ti_pr = IPPROTO_TCP; + n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); + n->ti_src = so->so_faddr; + 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; + n->ti_off = 5; + n->ti_flags = 0; + n->ti_win = 0; + n->ti_sum = 0; + n->ti_urp = 0; +} + +/* + * Send a single message to the TCP at address specified by + * the given TCP/IP header. If m == 0, then we make a copy + * of the tcpiphdr at ti and send directly to the addressed host. + * This is used to force keep alive messages out using the TCP + * template for a connection tp->t_template. If flags are given + * then we send a message back to the TCP which originated the + * segment ti, and discard the SLIRPmbuf containing it and any other + * attached SLIRPmbufs. + * + * In any case the ack and sequence number of the transmitted + * segment are as specified by the parameters. + */ +void +tcp_respond(tp, ti, m, ack, seq, flags) + struct tcpcb *tp; + struct tcpiphdr *ti; + struct SLIRPmbuf *m; + tcp_seq ack, seq; + int flags; +{ + register int tlen; + int win = 0; + + DEBUG_CALL("tcp_respond"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("ti = %lx", (long)ti); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("ack = %u", ack); + DEBUG_ARG("seq = %u", seq); + DEBUG_ARG("flags = %x", flags); + + if (tp) + win = sbspace(&tp->t_socket->so_rcv); + if (m == 0) { + if ((m = m_get()) == NULL) + return; +#ifdef TCP_COMPAT_42 + tlen = 1; +#else + tlen = 0; +#endif + m->m_data += if_maxlinkhdr; + *mtod(m, struct tcpiphdr *) = *ti; + ti = mtod(m, struct tcpiphdr *); + flags = TH_ACK; + } else { + /* + * ti points into m so the next line is just making + * the SLIRPmbuf point to ti + */ + m->m_data = (SLIRPcaddr_t)ti; + + m->m_len = sizeof (struct tcpiphdr); + tlen = 0; +#define xchg(a,b,type) { type t; t=a; a=b; b=t; } + xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t); + xchg(ti->ti_dport, ti->ti_sport, u_int16_t); +#undef xchg + } + ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); + tlen += sizeof (struct tcpiphdr); + m->m_len = tlen; + + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_seq = htonl(seq); + ti->ti_ack = htonl(ack); + ti->ti_x2 = 0; + ti->ti_off = sizeof (struct tcphdr) >> 2; + ti->ti_flags = flags; + if (tp) + ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale)); + else + ti->ti_win = htons((u_int16_t)win); + ti->ti_urp = 0; + ti->ti_sum = 0; + ti->ti_sum = cksum(m, tlen); + ((struct ip *)ti)->ip_len = tlen; + + if(flags & TH_RST) + ((struct ip *)ti)->ip_ttl = MAXTTL; + else + ((struct ip *)ti)->ip_ttl = ip_defttl; + + (void) ip_output((struct SLIRPsocket *)0, m); +} + +/* + * Create a new TCP control block, making an + * empty reassembly queue and hooking it to the argument + * protocol control block. + */ +struct tcpcb * +tcp_newtcpcb(so) + struct SLIRPsocket *so; +{ + 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 + * reasonable initial retransmit time. + */ + tp->t_srtt = TCPTV_SRTTBASE; + tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; + tp->t_rttmin = TCPTV_MIN; + + 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); +} + +/* + * Drop a TCP connection, reporting + * the specified error. If connection is synchronized, + * then send a RST to peer. + */ +struct tcpcb *tcp_drop(struct tcpcb *tp, int err) +{ +/* tcp_drop(tp, errno) + struct tcpcb *tp; + int errno; +{ +*/ + + 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); + tcpstat.tcps_drops++; + } else + tcpstat.tcps_conndrops++; +/* if (errno == ETIMEDOUT && tp->t_softerror) + * errno = tp->t_softerror; + */ +/* so->so_error = errno; */ + return (tcp_close(tp)); +} + +/* + * Close a TCP control block: + * discard all space held by the tcp + * discard internet protocol block + * wake up any sleepers + */ +struct tcpcb * +tcp_close(tp) + struct tcpcb *tp; +{ + struct tcpiphdr *t; + struct SLIRPsocket *so = tp->t_socket; + struct SLIRPmbuf *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 SLIRPmbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); + remque_32((struct tcpiphdr *) t->ti_prev); + m_freem(m); + } + /* It's static */ +/* if (tp->t_template) + * (void) m_free(dtom(tp->t_template)); + */ +/* free(tp, M_PCB); */ + free(tp); + so->so_tcpcb = 0; + soisfdisconnected(so); + /* clobber input socket cache if we're closing the cached connection */ + if (so == tcp_last_so) + tcp_last_so = &tcb; + closesocket(so->s); + sbfree(&so->so_rcv); + sbfree(&so->so_snd); + sofree(so); + tcpstat.tcps_closed++; + return ((struct tcpcb *)0); +} + +void +tcp_drain() +{ + /* XXX */ +} + +/* + * When a source quench is received, close congestion window + * to one segment. We will gradually open it again as we proceed. + */ + +#ifdef notdef + +void +tcp_quench(i, errno) + + int errno; +{ + struct tcpcb *tp = intotcpcb(inp); + + if (tp) + tp->snd_cwnd = tp->t_maxseg; +} + +#endif /* notdef */ + +/* + * TCP protocol interface to socket abstraction. + */ + +/* + * User issued close, and wish to trail through shutdown states: + * if never received SYN, just forget it. If got a SYN from peer, + * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. + * If already got a FIN from peer, then almost done; go to LAST_ACK + * state. In all other cases, have already sent FIN to peer (e.g. + * after PRU_SHUTDOWN), and just have to play tedious game waiting + * for peer to send FIN or not respond to keep-alives, etc. + * We can let the user exit from the close as soon as the FIN is acked. + */ +void +tcp_sockclosed(tp) + struct tcpcb *tp; +{ + + DEBUG_CALL("tcp_sockclosed"); + DEBUG_ARG("tp = %lx", (long)tp); + + switch (tp->t_state) { + + case TCPS_CLOSED: + case TCPS_LISTEN: + case TCPS_SYN_SENT: + tp->t_state = TCPS_CLOSED; + tp = tcp_close(tp); + break; + + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + tp->t_state = TCPS_FIN_WAIT_1; + break; + + case TCPS_CLOSE_WAIT: + tp->t_state = TCPS_LAST_ACK; + break; + } +/* soisfdisconnecting(tp->t_socket); */ + if (tp && tp->t_state >= TCPS_FIN_WAIT_2) + soisfdisconnected(tp->t_socket); + if (tp) + tcp_output(tp); +} + +/* + * 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 + * not wait for ACK+SYN. + */ +int tcp_fconnect(so) + struct SLIRPsocket *so; +{ + int ret=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; + struct sockaddr_in addr; + memset(&addr, 0, sizeof(struct sockaddr_in)); + + 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 )); + + 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 + addr.sin_addr = so->so_faddr; + 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))); + /* 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 + */ + soisfconnecting(so); + } + + return(ret); +} + +/* + * 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 + * 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 SLIRPsocket *inso; +{ + struct SLIRPsocket *so; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct tcpcb *tp; + int s, opt; + + 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. + */ + if (inso->so_state & SS_FACCEPTONCE) { + /* FACCEPTONCE already have a tcpcb */ + so = inso; + } else { + if ((so = socreate()) == NULL) { + /* If it failed, get rid of the pending connection */ + closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); + return; + } + if (tcp_attach(so) < 0) { + free(so); /* NOT sofree */ + return; + } + 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)); + opt = 1; + setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int)); + + 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 */ + 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) + * tp->request_r_scale++; + */ + +/* 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; + tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + tcp_output(tp); +} + +/* + * Attach a TCPCB to a socket. + */ +int +tcp_attach(so) + struct SLIRPsocket *so; +{ + if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) + return -1; + + insque(so, &tcb); + + return 0; +} + +/* + * Set the socket's type of service field + */ +struct tos_t tcptos[] = { + {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ + {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ + {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ + {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */ + {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */ + {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */ + {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */ + {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */ + {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */ + {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */ + {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ + {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ + {0, 0, 0, 0} +}; + +struct emu_t *tcpemu = 0; + +/* + * Return TOS according to the above table + */ +u_int8_t +tcp_tos(so) + struct SLIRPsocket *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))) { + so->so_emu = tcptos[i].emu; + return tcptos[i].tos; + } + 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; +} + +int do_echo = -1; + +/* + * Emulate programs that try and connect to us + * 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 SLIRPmbuf m is still valid and should be + * sbappend()ed + * + * NOTE: if you return 0 you MUST m_free() the SLIRPmbuf! + */ +int +tcp_emu(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *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 SLIRPsocket *tmpso; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct 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; + m->m_data[m->m_len] = 0; /* NULL terminate */ + if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { + if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) { + HTONS(n1); + HTONS(n2); + /* n2 is the one on our host */ + for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { + if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && + tmpso->so_lport == n2 && + tmpso->so_faddr.s_addr == so->so_faddr.s_addr && + tmpso->so_fport == n1) { + if (getsockname(tmpso->s, + (struct sockaddr *)&addr, &addrlen) == 0) + n2 = ntohs(addr.sin_port); + break; + } + } + } + so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2); + so_rcv->sb_rptr = so_rcv->sb_data; + so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; + } + m_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 SLIRPsocket *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]", + &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", + n1, n2, n3, n4, n5, n6, x==7?buff:""); + return 1; + } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { + /* + * Need to emulate the PASV response + */ + x = sscanf(bptr, "27 Entering Passive Mode (%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,"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 + * a local port port number to carry signals to the server + * and stderr to the client. It is passed at the beginning + * of the connection as a NUL-terminated decimal ASCII string. + */ + so->so_emu = 0; + for (lport = 0, i = 0; i < m->m_len-1; ++i) { + if (m->m_data[i] < '0' || m->m_data[i] > '9') + return 1; /* invalid number */ + lport *= 10; + lport += m->m_data[i] - '0'; + } + if (m->m_data[m->m_len-1] == '\0' && lport != 0 && + (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 + */ + *(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), + ntohs(so->so_fport), 1); + } 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", + 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), + ntohs(so->so_fport), n1, 1); + } + 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 + * number with the real port we got. + * + * 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: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]; + + ra_tbl[0] = 0x50; + ra_tbl[1] = 0x4e; + ra_tbl[2] = 0x41; + ra_tbl[3] = 0; + + switch (ra) { + case 0: + case 2: + case 3: + if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; + + case 1: + /* + * We may get 0x50 several times, ignore them + */ + if (*bptr == 0x50) { + ra = 1; + bptr++; + continue; + } else if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; + + case 4: + /* + * skip version number + */ + bptr++; + break; + + case 5: + /* + * The difference between versions 1.0 and + * 2.0 is here. For future versions of + * the player this may need to be modified. + */ + if (*(bptr + 1) == 0x02) + bptr += 8; + else + bptr += 4; + break; + + case 6: + /* This is the field containing the port + * number that RA-player is listening to. + */ + lport = (((u_char*)bptr)[0] << 8) + + ((u_char *)bptr)[1]; + 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), + so->so_laddr.s_addr, + htons(lport), + SS_FACCEPTONCE)) { + break; + } + } + if (p == 7071) + p = 0; + *(u_char *)bptr++ = (p >> 8) & 0xff; + *(u_char *)bptr++ = p & 0xff; + ra = 0; + return 1; /* port redirected, we're done */ + break; + + default: + ra = 0; + } + ra++; + } + return 1; + + default: + /* Ooops, not emulated, won't call tcp_emu again */ + so->so_emu = 0; + return 1; + } +} + +/* + * Do misc. config of SLiRP while its running. + * Return 0 if this connections is to be closed, 1 otherwise, + * return 2 if this is a command-line connection + */ +int +tcp_ctl(so) + struct SLIRPsocket *so; +{ + struct sbuf *sb = &so->so_snd; + int command; + struct ex_list *ex_ptr; + int do_pty; + // struct SLIRPsocket *tmpso; + + DEBUG_CALL("tcp_ctl"); + DEBUG_ARG("so = %lx", (long )so); + +#if 0 + /* + * Check if they're authorised + */ + if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) { + sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n"); + sb->sb_wptr += sb->sb_cc; + return 0; + } +#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; + } + } + + /* + * 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/src/slirp/tcp_timer.c b/src/slirp/tcp_timer.c new file mode 100644 index 000000000..892b222c7 --- /dev/null +++ b/src/slirp/tcp_timer.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93 + * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp + */ + +#include "slirp.h" + +int tcp_keepidle = TCPTV_KEEP_IDLE; +int tcp_keepintvl = TCPTV_KEEPINTVL; +int tcp_maxidle; +int so_options = DO_KEEPALIVE; + +struct tcpstat tcpstat; /* tcp statistics */ +u_int32_t tcp_now; /* for RFC 1323 timestamps */ + +/* + * Fast timeout routine for processing delayed acks + */ +void +tcp_fasttimo() +{ + register struct SLIRPsocket *so; + register struct tcpcb *tp; + + DEBUG_CALL("tcp_fasttimo"); + + so = tcb.so_next; + if (so) + for (; so != &tcb; so = so->so_next) + if ((tp = (struct tcpcb *)so->so_tcpcb) && + (tp->t_flags & TF_DELACK)) { + tp->t_flags &= ~TF_DELACK; + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_delack++; + (void) tcp_output(tp); + } +} + +/* + * Tcp protocol timeout routine called every 500 ms. + * Updates the timers in all active tcb's and + * causes finite state machine actions if timers expire. + */ +void +tcp_slowtimo() +{ + register struct SLIRPsocket *ip, *ipnxt; + register struct tcpcb *tp; + register int i; + + DEBUG_CALL("tcp_slowtimo"); + + tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; + /* + * Search through tcb's and update active timers. + */ + ip = tcb.so_next; + if (ip == 0) + return; + for (; ip != &tcb; ip = ipnxt) { + ipnxt = ip->so_next; + tp = sototcpcb(ip); + if (tp == 0) + continue; + for (i = 0; i < TCPT_NTIMERS; i++) { + if (tp->t_timer[i] && --tp->t_timer[i] == 0) { + tcp_timers(tp,i); + if (ipnxt->so_prev != ip) + goto tpgone; + } + } + tp->t_idle++; + if (tp->t_rtt) + tp->t_rtt++; +tpgone: + ; + } + tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ +#ifdef TCP_COMPAT_42 + if ((int)tcp_iss < 0) + tcp_iss = 0; /* XXX */ +#endif + tcp_now++; /* for timestamps */ +} + +/* + * Cancel all timers for TCP tp. + */ +void +tcp_canceltimers(tp) + struct tcpcb *tp; +{ + register int i; + + for (i = 0; i < TCPT_NTIMERS; i++) + tp->t_timer[i] = 0; +} + +int tcp_backoff[TCP_MAXRXTSHIFT + 1] = + { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; + +/* + * TCP timer processing. + */ +struct tcpcb * +tcp_timers(tp, timer) + struct tcpcb *tp; + int timer; +{ + int rexmt; + + DEBUG_CALL("tcp_timers"); + + switch (timer) { + + /* + * 2 MSL timeout in shutdown went off. If we're closed but + * still waiting for peer to close and connection has been idle + * too long, or if 2MSL time is up from TIME_WAIT, delete connection + * control block. Otherwise, check again in a bit. + */ + case TCPT_2MSL: + if (tp->t_state != TCPS_TIME_WAIT && + tp->t_idle <= tcp_maxidle) + tp->t_timer[TCPT_2MSL] = tcp_keepintvl; + else + tp = tcp_close(tp); + break; + + /* + * Retransmission timer went off. Message has not + * been acked within retransmit interval. Back off + * to a longer retransmit interval and retransmit one segment. + */ + case TCPT_REXMT: + + /* + * XXXXX If a packet has timed out, then remove all the queued + * packets for that session. + */ + + if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { + /* + * This is a hack to suit our terminal server here at the uni of canberra + * since they have trouble with zeroes... It usually lets them through + * unharmed, but under some conditions, it'll eat the zeros. If we + * keep retransmitting it, it'll keep eating the zeroes, so we keep + * retransmitting, and eventually the connection dies... + * (this only happens on incoming data) + * + * So, if we were gonna drop the connection from too many retransmits, + * don't... instead halve the t_maxseg, which might break up the NULLs and + * let them through + * + * *sigh* + */ + + tp->t_maxseg >>= 1; + if (tp->t_maxseg < 32) { + /* + * We tried our best, now the connection must die! + */ + tp->t_rxtshift = TCP_MAXRXTSHIFT; + tcpstat.tcps_timeoutdrop++; + tp = tcp_drop(tp, tp->t_softerror); + /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ + return (tp); /* XXX */ + } + + /* + * Set rxtshift to 6, which is still at the maximum + * backoff time + */ + tp->t_rxtshift = 6; + } + tcpstat.tcps_rexmttimeo++; + rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; + TCPT_RANGESET(tp->t_rxtcur, rexmt, + (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * If losing, let the lower level know and try for + * a better route. Also, if we backed off this far, + * our srtt estimate is probably bogus. Clobber it + * so we'll take the next rtt measurement as our srtt; + * move the current srtt into rttvar to keep the current + * retransmit times until then. + */ + if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { +/* in_losing(tp->t_inpcb); */ + tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); + tp->t_srtt = 0; + } + tp->snd_nxt = tp->snd_una; + /* + * If timing a segment in this window, stop the timer. + */ + tp->t_rtt = 0; + /* + * Close the congestion window down to one segment + * (we'll open it by one segment for each ack we get). + * Since we probably have a window's worth of unacked + * data accumulated, this "slow start" keeps us from + * dumping all that data as back-to-back packets (which + * might overwhelm an intermediate gateway). + * + * There are two phases to the opening: Initially we + * open by one mss on each ack. This makes the window + * size increase exponentially with time. If the + * window is larger than the path can handle, this + * exponential growth results in dropped packet(s) + * almost immediately. To get more time between + * drops but still "push" the network to take advantage + * of improving conditions, we switch from exponential + * to linear window opening at some threshold size. + * For a threshold, we use half the current window + * size, truncated to a multiple of the mss. + * + * (the minimum cwnd that will give us exponential + * growth is 2 mss. We don't allow the threshold + * to go below this.) + */ + { + u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; + if (win < 2) + win = 2; + tp->snd_cwnd = tp->t_maxseg; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_dupacks = 0; + } + (void) tcp_output(tp); + break; + + /* + * Persistence timer into zero window. + * Force a byte to be output, if possible. + */ + case TCPT_PERSIST: + tcpstat.tcps_persisttimeo++; + tcp_setpersist(tp); + tp->t_force = 1; + (void) tcp_output(tp); + tp->t_force = 0; + break; + + /* + * Keep-alive timer went off; send something + * or drop connection if idle for too long. + */ + case TCPT_KEEP: + tcpstat.tcps_keeptimeo++; + if (tp->t_state < TCPS_ESTABLISHED) + goto dropit; + +/* if (tp->t_socket->so_options & SO_KEEPALIVE && */ + if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) { + if (tp->t_idle >= tcp_keepidle + tcp_maxidle) + goto dropit; + /* + * Send a packet designed to force a response + * if the peer is up and reachable: + * either an ACK if the connection is still alive, + * or an RST if the peer has closed the connection + * due to timeout or reboot. + * Using sequence number tp->snd_una-1 + * causes the transmitted zero-length segment + * to lie outside the receive window; + * by the protocol spec, this requires the + * correspondent TCP to respond. + */ + tcpstat.tcps_keepprobe++; +#ifdef TCP_COMPAT_42 + /* + * The keepalive packet must have nonzero length + * to get a 4.2 host to respond. + */ + tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL, + tp->rcv_nxt - 1, tp->snd_una - 1, 0); +#else + tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL, + tp->rcv_nxt, tp->snd_una - 1, 0); +#endif + tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + } else + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + break; + + dropit: + tcpstat.tcps_keepdrops++; + tp = tcp_drop(tp, 0); /* ETIMEDOUT); */ + break; + } + + return (tp); +} diff --git a/src/slirp/tcp_timer.h b/src/slirp/tcp_timer.h new file mode 100644 index 000000000..0bc438c76 --- /dev/null +++ b/src/slirp/tcp_timer.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 + * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp + */ + +#ifndef _TCP_TIMER_H_ +#define _TCP_TIMER_H_ + +/* + * Definitions of the TCP timers. These timers are counted + * down PR_SLOWHZ times a second. + */ +#define TCPT_NTIMERS 4 + +#define TCPT_REXMT 0 /* retransmit */ +#define TCPT_PERSIST 1 /* retransmit persistence */ +#define TCPT_KEEP 2 /* keep alive */ +#define TCPT_2MSL 3 /* 2*msl quiet time timer */ + +/* + * The TCPT_REXMT timer is used to force retransmissions. + * The TCP has the TCPT_REXMT timer set whenever segments + * have been sent for which ACKs are expected but not yet + * received. If an ACK is received which advances tp->snd_una, + * then the retransmit timer is cleared (if there are no more + * outstanding segments) or reset to the base value (if there + * are more ACKs expected). Whenever the retransmit timer goes off, + * we retransmit one unacknowledged segment, and do a backoff + * on the retransmit timer. + * + * The TCPT_PERSIST timer is used to keep window size information + * flowing even if the window goes shut. If all previous transmissions + * have been acknowledged (so that there are no retransmissions in progress), + * and the window is too small to bother sending anything, then we start + * the TCPT_PERSIST timer. When it expires, if the window is nonzero, + * we go to transmit state. Otherwise, at intervals send a single byte + * into the peer's window to force him to update our window information. + * We do this at most as often as TCPT_PERSMIN time intervals, + * but no more frequently than the current estimate of round-trip + * packet time. The TCPT_PERSIST timer is cleared whenever we receive + * a window update from the peer. + * + * The TCPT_KEEP timer is used to keep connections alive. If an + * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, + * but not yet established, then we drop the connection. Once the connection + * is established, if the connection is idle for TCPTV_KEEP_IDLE time + * (and keepalives have been enabled on the socket), we begin to probe + * the connection. We force the peer to send us a segment by sending: + * + * This segment is (deliberately) outside the window, and should elicit + * an ack segment in response from the peer. If, despite the TCPT_KEEP + * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE + * amount of time probing, then we drop the connection. + */ + +/* + * Time constants. + */ +#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ + +#define TCPTV_SRTTBASE 0 /* base roundtrip time; + if 0, no idea yet */ +#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ + +#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ +#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ + +#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ +#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ +#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ +#define TCPTV_KEEPCNT 8 /* max probes before drop */ + +#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ +/* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */ +#define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */ + +#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ + +#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ + + +#ifdef TCPTIMERS +char *tcptimers[] = + { "REXMT", "PERSIST", "KEEP", "2MSL" }; +#endif + +/* + * Force a time value to be in a certain range. + */ +#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ + (tv) = (value); \ + if ((tv) < (tvmin)) \ + (tv) = (tvmin); \ + else if ((tv) > (tvmax)) \ + (tv) = (tvmax); \ +} + +extern int tcp_keepidle; /* time before keepalive probes begin */ +extern int tcp_keepintvl; /* time between keepalive probes */ +extern int tcp_maxidle; /* time to drop after starting probes */ +extern int tcp_ttl; /* time to live for TCP segs */ +extern int tcp_backoff[]; + +struct tcpcb; + +void tcp_fasttimo _P((void)); +void tcp_slowtimo _P((void)); +void tcp_canceltimers _P((struct tcpcb *)); +struct tcpcb * tcp_timers _P((register struct tcpcb *, int)); + +#endif diff --git a/src/slirp/tcp_var.h b/src/slirp/tcp_var.h new file mode 100644 index 000000000..e8f6bb73f --- /dev/null +++ b/src/slirp/tcp_var.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1982, 1986, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_var.h 8.3 (Berkeley) 4/10/94 + * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp + */ + +#ifndef _TCP_VAR_H_ +#define _TCP_VAR_H_ + +#include "tcpip.h" +#include "tcp_timer.h" + +#if SIZEOF_CHAR_P == 4 + typedef struct tcpiphdr *tcpiphdrp_32; +#else + typedef u_int32_t tcpiphdrp_32; +#endif + +/* + * Tcp control block, one per tcp; fields: + */ +struct tcpcb { + tcpiphdrp_32 seg_next; /* sequencing queue */ + tcpiphdrp_32 seg_prev; + short t_state; /* state of this connection */ + short t_timer[TCPT_NTIMERS]; /* tcp timers */ + short t_rxtshift; /* log(2) of rexmt exp. backoff */ + short t_rxtcur; /* current retransmit value */ + short t_dupacks; /* consecutive dup acks recd */ + u_short t_maxseg; /* maximum segment size */ + char t_force; /* 1 if forcing out a byte */ + u_short t_flags; +#define TF_ACKNOW 0x0001 /* ack peer immediately */ +#define TF_DELACK 0x0002 /* ack, but try to delay it */ +#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ +#define TF_NOOPT 0x0008 /* don't use tcp options */ +#define TF_SENTFIN 0x0010 /* have sent FIN */ +#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ +#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ +#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ +#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ +#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ + + /* Make it static for now */ +/* struct tcpiphdr *t_template; / * skeletal packet for transmit */ + struct tcpiphdr t_template; + + struct SLIRPsocket *t_socket; /* back pointer to socket */ +/* + * The following fields are used as in the protocol specification. + * See RFC783, Dec. 1981, page 21. + */ +/* send sequence variables */ + tcp_seq snd_una; /* send unacknowledged */ + tcp_seq snd_nxt; /* send next */ + tcp_seq snd_up; /* send urgent pointer */ + tcp_seq snd_wl1; /* window update seg seq number */ + tcp_seq snd_wl2; /* window update seg ack number */ + tcp_seq iss; /* initial send sequence number */ + u_int32_t snd_wnd; /* send window */ +/* receive sequence variables */ + u_int32_t rcv_wnd; /* receive window */ + tcp_seq rcv_nxt; /* receive next */ + tcp_seq rcv_up; /* receive urgent pointer */ + tcp_seq irs; /* initial receive sequence number */ +/* + * Additional variables for this implementation. + */ +/* receive variables */ + tcp_seq rcv_adv; /* advertised window */ +/* retransmit variables */ + tcp_seq snd_max; /* highest sequence number sent; + * used to recognize retransmits + */ +/* congestion control (for slow start, source quench, retransmit after loss) */ + u_int32_t snd_cwnd; /* congestion-controlled window */ + u_int32_t snd_ssthresh; /* snd_cwnd size threshold for + * for slow start exponential to + * linear switch + */ +/* + * transmit timing stuff. See below for scale of srtt and rttvar. + * "Variance" is actually smoothed difference. + */ + short t_idle; /* inactivity time */ + short t_rtt; /* round trip time */ + tcp_seq t_rtseq; /* sequence number being timed */ + short t_srtt; /* smoothed round-trip time */ + short t_rttvar; /* variance in round-trip time */ + u_short t_rttmin; /* minimum rtt allowed */ + u_int32_t max_sndwnd; /* largest window peer has offered */ + +/* out-of-band data */ + char t_oobflags; /* have some */ + char t_iobc; /* input character */ +#define TCPOOB_HAVEDATA 0x01 +#define TCPOOB_HADDATA 0x02 + short t_softerror; /* possible error not yet reported */ + +/* RFC 1323 variables */ + u_char snd_scale; /* window scaling for send window */ + u_char rcv_scale; /* window scaling for recv window */ + u_char request_r_scale; /* pending window scaling */ + u_char requested_s_scale; + u_int32_t ts_recent; /* timestamp echo data */ + u_int32_t ts_recent_age; /* when last updated */ + tcp_seq last_ack_sent; + +}; + +#define sototcpcb(so) ((so)->so_tcpcb) + +/* + * The smoothed round-trip time and estimated variance + * are stored as fixed point numbers scaled by the values below. + * For convenience, these scales are also used in smoothing the average + * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). + * With these scales, srtt has 3 bits to the right of the binary point, + * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the + * binary point, and is smoothed with an ALPHA of 0.75. + */ +#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ +#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ +#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ +#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ + +/* + * The initial retransmission should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + * This macro assumes that the value of TCP_RTTVAR_SCALE + * is the same as the multiplier for rttvar. + */ +#define TCP_REXMTVAL(tp) \ + (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) + +/* 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 + * 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 SLIRPmbuf *mbufp_32; +#else +typedef u_int32_t mbufp_32; +#endif +#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) + +/* + * TCP statistics. + * Many of these should be kept per connection, + * but that's inconvenient at the moment. + */ +struct tcpstat { + u_long tcps_connattempt; /* connections initiated */ + u_long tcps_accepts; /* connections accepted */ + u_long tcps_connects; /* connections established */ + u_long tcps_drops; /* connections dropped */ + u_long tcps_conndrops; /* embryonic connections dropped */ + u_long tcps_closed; /* conn. closed (includes drops) */ + u_long tcps_segstimed; /* segs where we tried to get rtt */ + u_long tcps_rttupdated; /* times we succeeded */ + u_long tcps_delack; /* delayed acks sent */ + u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ + u_long tcps_rexmttimeo; /* retransmit timeouts */ + u_long tcps_persisttimeo; /* persist timeouts */ + u_long tcps_keeptimeo; /* keepalive timeouts */ + u_long tcps_keepprobe; /* keepalive probes sent */ + u_long tcps_keepdrops; /* connections dropped in keepalive */ + + u_long tcps_sndtotal; /* total packets sent */ + u_long tcps_sndpack; /* data packets sent */ + u_long tcps_sndbyte; /* data bytes sent */ + u_long tcps_sndrexmitpack; /* data packets retransmitted */ + u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ + u_long tcps_sndacks; /* ack-only packets sent */ + u_long tcps_sndprobe; /* window probes sent */ + u_long tcps_sndurg; /* packets sent with URG only */ + u_long tcps_sndwinup; /* window update-only packets sent */ + u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ + + u_long tcps_rcvtotal; /* total packets received */ + u_long tcps_rcvpack; /* packets received in sequence */ + u_long tcps_rcvbyte; /* bytes received in sequence */ + u_long tcps_rcvbadsum; /* packets received with ccksum errs */ + u_long tcps_rcvbadoff; /* packets received with bad offset */ +/* u_long tcps_rcvshort; */ /* packets received too short */ + u_long tcps_rcvduppack; /* duplicate-only packets received */ + u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ + u_long tcps_rcvpartduppack; /* packets with some duplicate data */ + u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ + u_long tcps_rcvoopack; /* out-of-order packets received */ + u_long tcps_rcvoobyte; /* out-of-order bytes received */ + u_long tcps_rcvpackafterwin; /* packets with data after window */ + u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ + u_long tcps_rcvafterclose; /* packets rcvd after "close" */ + u_long tcps_rcvwinprobe; /* rcvd window probe packets */ + u_long tcps_rcvdupack; /* rcvd duplicate acks */ + u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ + u_long tcps_rcvackpack; /* rcvd ack packets */ + u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ + u_long tcps_rcvwinupd; /* rcvd window update packets */ +/* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */ + u_long tcps_predack; /* times hdr predict ok for acks */ + u_long tcps_preddat; /* times hdr predict ok for data pkts */ + u_long tcps_socachemiss; /* tcp_last_so misses */ + u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */ +}; + +extern struct tcpstat tcpstat; /* tcp statistics */ +extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ + +#endif diff --git a/src/slirp/tcpip.h b/src/slirp/tcpip.h new file mode 100644 index 000000000..dff5a3c96 --- /dev/null +++ b/src/slirp/tcpip.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 + * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp + */ + +#ifndef _TCPIP_H_ +#define _TCPIP_H_ + +/* + * Tcp+ip header, after ip options removed. + */ +struct tcpiphdr { + struct ipovly ti_i; /* overlaid ip structure */ + struct tcphdr ti_t; /* tcp header */ +}; +#define ti_next ti_i.ih_next +#define ti_prev ti_i.ih_prev +#define ti_x1 ti_i.ih_x1 +#define ti_pr ti_i.ih_pr +#define ti_len ti_i.ih_len +#define ti_src ti_i.ih_src +#define ti_dst ti_i.ih_dst +#define ti_sport ti_t.th_sport +#define ti_dport ti_t.th_dport +#define ti_seq ti_t.th_seq +#define ti_ack ti_t.th_ack +#define ti_x2 ti_t.th_x2 +#define ti_off ti_t.th_off +#define ti_flags ti_t.th_flags +#define ti_win ti_t.th_win +#define ti_sum ti_t.th_sum +#define ti_urp ti_t.th_urp + +/* + * Just a clean way to get to the first byte + * of the packet + */ +struct tcpiphdr_2 { + struct tcpiphdr dummy; + char first_char; +}; + +#endif diff --git a/src/slirp/tftp.c b/src/slirp/tftp.c new file mode 100644 index 000000000..b7b1ffb0a --- /dev/null +++ b/src/slirp/tftp.c @@ -0,0 +1,332 @@ +/* + * tftp.c - a simple, read-only tftp server for qemu + * + * Copyright (c) 2004 Magnus Damm + * + * 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 "slirp.h" +#include "../ibm.h" + +struct tftp_session { + int in_use; + char filename[TFTP_FILENAME_MAX]; + + struct in_addr client_ip; + u_int16_t client_port; + + int timestamp; +}; + +struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; + +const char *tftp_prefix; + +static void tftp_session_update(struct tftp_session *spt) +{ + spt->timestamp = curtime; + spt->in_use = 1; +} + +static void tftp_session_terminate(struct tftp_session *spt) +{ + spt->in_use = 0; +} + +static int tftp_session_allocate(struct tftp_t *tp) +{ + struct tftp_session *spt; + int k; + + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &tftp_sessions[k]; + + if (!spt->in_use) + goto found; + + /* sessions time out after 5 inactive seconds */ + if ((int)(curtime - spt->timestamp) > 5000) + goto found; + } + + return -1; + + found: + memset(spt, 0, sizeof(*spt)); + memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); + spt->client_port = tp->udp.uh_sport; + + tftp_session_update(spt); + + return k; +} + +static int tftp_session_find(struct tftp_t *tp) +{ + struct tftp_session *spt; + int k; + + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &tftp_sessions[k]; + + if (spt->in_use) { + if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) { + if (spt->client_port == tp->udp.uh_sport) { + return k; + } + } + } + } + + return -1; +} + +static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, + u_int8_t *buf, int len) +{ + int fd; + int bytes_read = 0; + + char file_path[sizeof(pcempath) + 5 + sizeof(spt->filename)]; + strcpy(file_path, pcempath); + strcat(file_path, "tftp/"); + strcat(file_path, spt->filename); + + fd = open(file_path, O_RDONLY | O_BINARY); + + if (fd < 0) { + return -1; + } + + if (len) { + lseek(fd, block_nr * 512, SEEK_SET); + + bytes_read = read(fd, buf, len); + } + + close(fd); + + return bytes_read; +} + +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 SLIRPmbuf *m; + struct tftp_t *tp; + int nobytes; + + m = m_get(); + + if (!m) { + return -1; + } + + memset(m->m_data, 0, m->m_size); + + m->m_data += if_maxlinkhdr; + tp = (void *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_ERROR); + tp->x.tp_error.tp_error_code = htons(errorcode); + strncpy((char *)tp->x.tp_error.tp_msg, msg, sizeof(tp->x.tp_error.tp_msg)); + tp->x.tp_error.tp_msg[sizeof(tp->x.tp_error.tp_msg)-1] = 0; + + 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; + + nobytes = 2; + + 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); + + tftp_session_terminate(spt); + + return 0; +} + +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 SLIRPmbuf *m; + struct tftp_t *tp; + int nobytes; + + if (block_nr < 1) { + return -1; + } + + m = m_get(); + + if (!m) { + return -1; + } + + memset(m->m_data, 0, m->m_size); + + m->m_data += if_maxlinkhdr; + tp = (void *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_DATA); + tp->x.tp_data.tp_block_nr = htons(block_nr); + + 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; + + nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); + + if (nobytes < 0) { + m_free(m); + + /* send "file not found" error back */ + + tftp_send_error(spt, 1, "File not found", tp); + + return -1; + } + + m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - + sizeof(struct ip) - sizeof(struct udphdr); + + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + + if (nobytes == 512) { + tftp_session_update(spt); + } + else { + tftp_session_terminate(spt); + } + + return 0; +} + +static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) +{ + struct tftp_session *spt; + int s, k, n; + u_int8_t *src, *dst; + + s = tftp_session_allocate(tp); + + if (s < 0) { + return; + } + + spt = &tftp_sessions[s]; + + src = tp->x.tp_buf; + dst = (u_int8_t *)spt->filename; + n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp); + + /* get name */ + + for (k = 0; k < n; k++) { + if (k < TFTP_FILENAME_MAX) { + dst[k] = src[k]; + } + 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; + } + + pclog("tftp request: %s\n", spt->filename); + + /* do sanity checks on the filename */ + + if (strstr(spt->filename, "../") || strstr(spt->filename, "..\\")) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + /* check if the file exists */ + + if (tftp_read_data(spt, 0, (u_int8_t *)spt->filename, 0) < 0) { + tftp_send_error(spt, 1, "File not found", tp); + return; + } + + tftp_send_data(spt, 1, tp); +} + +static void tftp_handle_ack(struct tftp_t *tp, int pktlen) +{ + int s; + + s = tftp_session_find(tp); + + if (s < 0) { + return; + } + + if (tftp_send_data(&tftp_sessions[s], + ntohs(tp->x.tp_data.tp_block_nr) + 1, + tp) < 0) { + return; + } +} + +void tftp_input(struct SLIRPmbuf *m) +{ + struct tftp_t *tp = (struct tftp_t *)m->m_data; + + switch(ntohs(tp->tp_op)) { + case TFTP_RRQ: + tftp_handle_rrq(tp, m->m_len); + break; + + case TFTP_ACK: + tftp_handle_ack(tp, m->m_len); + break; + } +} diff --git a/src/slirp/tftp.h b/src/slirp/tftp.h new file mode 100644 index 000000000..ba4174115 --- /dev/null +++ b/src/slirp/tftp.h @@ -0,0 +1,40 @@ +/* tftp defines */ + +#define TFTP_SESSIONS_MAX 3 + +#define TFTP_SERVER 69 + +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 + +#define TFTP_FILENAME_MAX 512 + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct tftp_t { + struct ip ip; + struct udphdr udp; + u_int16_t tp_op; + union { + struct { + u_int16_t tp_block_nr; + u_int8_t tp_buf[512]; + } tp_data; + struct { + u_int16_t tp_error_code; + u_int8_t tp_msg[512]; + } tp_error; + u_int8_t tp_buf[512 + 2]; + } x; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +void tftp_input(struct SLIRPmbuf *m); diff --git a/src/slirp/udp.c b/src/slirp/udp.c new file mode 100644 index 000000000..318ac6400 --- /dev/null +++ b/src/slirp/udp.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 + * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "slirp.h" +#include "ip_icmp.h" + +struct udpstat udpstat; + +struct SLIRPsocket udb; + +/* + * UDP protocol implementation. + * Per RFC 768, August, 1980. + */ +#ifndef COMPAT_42 +int udpcksum = 1; +#else +int udpcksum = 0; /* XXX */ +#endif + +struct SLIRPsocket *udp_last_so = &udb; + +void +udp_init() +{ + udb.so_next = udb.so_prev = &udb; +} +/* 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) + struct SLIRPmbuf *m; + int iphlen; +{ + struct ip *ip; + struct udphdr *uh; +/* struct SLIRPmbuf *opts = 0;*/ + int len; + struct ip save_ip; + struct SLIRPsocket *so; + + DEBUG_CALL("udp_input"); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("iphlen = %d", iphlen); + + udpstat.udps_ipackets++; + + /* + * Strip IP options, if any; should skip this, + * make available to user, and use on returned packets, + * but we don't yet have a way to check the checksum + * with options still present. + */ + if(iphlen > sizeof(struct ip)) { + ip_stripoptions(m, (struct SLIRPmbuf *)0); + iphlen = sizeof(struct ip); + } + + /* + * Get IP and UDP header together in first SLIRPmbuf. + */ + ip = mtod(m, struct ip *); + uh = (struct udphdr *)((SLIRPcaddr_t)ip + iphlen); + + /* + * Make SLIRPmbuf data length reflect UDP length. + * If not enough data to reflect UDP length, drop. + */ + len = ntohs((u_int16_t)uh->uh_ulen); + + if (ip->ip_len != len) { + if (len > ip->ip_len) { + udpstat.udps_badlen++; + goto bad; + } + m_adj(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_len+= iphlen; /* tcp_input subtracts this */ + + /* + * Checksum extended UDP header and data. + */ + if (udpcksum && uh->uh_sum) { + ((struct ipovly *)ip)->ih_next = 0; + ((struct ipovly *)ip)->ih_prev = 0; + ((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) { + */ + if(cksum(m, len + sizeof(struct ip))) { + udpstat.udps_badsum++; + goto bad; + } + } + + /* + * handle DHCP/BOOTP + */ + if (ntohs(uh->uh_dport) == BOOTP_SERVER) { + bootp_input(m); + goto bad; + } + + /* + * handle TFTP + */ + if (ntohs(uh->uh_dport) == TFTP_SERVER) { + tftp_input(m); + goto bad; + } + + /* + * Locate pcb for datagram. + */ + so = udp_last_so; + if (so->so_lport != uh->uh_sport || + so->so_laddr.s_addr != ip->ip_src.s_addr) { + struct SLIRPsocket *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) { + tmp->so_faddr.s_addr = ip->ip_dst.s_addr; + tmp->so_fport = uh->uh_dport; + so = tmp; + break; + } + } + if (tmp == &udb) { + so = NULL; + } else { + udpstat.udpps_pcbcachemiss++; + udp_last_so = so; + } + } + + if (so == NULL) { + /* + * If there's no socket for this packet, + * create one + */ + if ((so = socreate()) == NULL) goto bad; + if(udp_attach(so) == -1) { + 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; + + 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. + */ + } + + 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; + + /* + * Now we sendto() the packet. + */ + if (so->so_emu) + udp_emu(so, m); + + if(sosendto(so,m) == -1) { + m->m_len += 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)); + } + + m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ + + /* restore the orig SLIRPmbuf packet */ + m->m_len += iphlen; + m->m_data -= iphlen; + *ip=save_ip; + so->so_m=m; /* ICMP backup */ + + return; +bad: + m_freem(m); + /* if (opts) m_freem(opts); */ + return; +} + +int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m, + struct sockaddr_in *saddr, struct sockaddr_in *daddr, + int iptos) +{ + struct udpiphdr *ui; + int error = 0; + + DEBUG_CALL("udp_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr); + DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr); + + /* + * Adjust for header + */ + m->m_data -= sizeof(struct udpiphdr); + m->m_len += sizeof(struct udpiphdr); + + /* + * Fill in SLIRPmbuf with extended UDP header + * and addresses and length put into network format. + */ + ui = mtod(m, struct udpiphdr *); + ui->ui_next = ui->ui_prev = 0; + ui->ui_x1 = 0; + ui->ui_pr = IPPROTO_UDP; + ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ + /* XXXXX Check for from-one-location sockets, or from-any-location sockets */ + ui->ui_src = saddr->sin_addr; + ui->ui_dst = daddr->sin_addr; + ui->ui_sport = saddr->sin_port; + ui->ui_dport = daddr->sin_port; + ui->ui_ulen = ui->ui_len; + + /* + * Stuff checksum and output datagram. + */ + ui->ui_sum = 0; + if (udpcksum) { + if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0) + ui->ui_sum = 0xffff; + } + ((struct ip *)ui)->ip_len = m->m_len; + + ((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 SLIRPsocket *so, struct SLIRPmbuf *m, + struct sockaddr_in *addr) + +{ + struct sockaddr_in saddr, daddr; + + saddr = *addr; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + saddr.sin_addr.s_addr = so->so_faddr.s_addr; + if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff)) + saddr.sin_addr.s_addr = alias_addr.s_addr; + } + daddr.sin_addr = so->so_laddr; + daddr.sin_port = so->so_lport; + + return udp_output2(so, m, &saddr, &daddr, so->so_iptos); +} + +int +udp_attach(so) + struct SLIRPsocket *so; +{ + struct sockaddr_in addr; + + if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { + /* + * Here, we bind() the socket. Although not really needed + * (sendto() on an unbound socket will bind it), it's done + * here so that emulation of ytalk etc. don't have to do it + */ + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { + int lasterrno=errno; + closesocket(so->s); + so->s=-1; +#ifdef _WIN32 + WSASetLastError(lasterrno); +#else + errno=lasterrno; +#endif + } else { + /* success, insert in queue */ + so->so_expire = curtime + SO_EXPIRE; + insque(so,&udb); + } + } + return(so->s); +} + +void +udp_detach(so) + struct SLIRPsocket *so; +{ + closesocket(so->s); + /* if (so->so_m) m_free(so->so_m); done by sofree */ + + sofree(so); +} + +struct tos_t udptos[] = { + {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ + {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ + {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ + {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */ + {0, 0, 0, 0} +}; + +u_int8_t +udp_tos(so) + struct SLIRPsocket *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)) { + so->so_emu = udptos[i].emu; + return udptos[i].tos; + } + i++; + } + + return 0; +} + +#ifdef EMULATE_TALK +#include "talkd.h" +#endif + +/* + * Here, talk/ytalk/ntalk requests must be emulated + */ +void +udp_emu(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); +#ifdef EMULATE_TALK + CTL_MSG_OLD *omsg; + CTL_MSG *nmsg; + char buff[sizeof(CTL_MSG)]; + u_char type; + +struct talk_request { + struct talk_request *next; + struct SLIRPsocket *udp_so; + struct SLIRPsocket *tcp_so; +} *req; + + static struct talk_request *req_tbl = 0; + +#endif + +struct cu_header { + uint16_t d_family; // destination family + uint16_t d_port; // destination port + uint32_t d_addr; // destination address + uint16_t s_family; // source family + uint16_t s_port; // source port + uint32_t so_addr; // source address + uint32_t seqn; // sequence number + uint16_t message; // message + uint16_t data_type; // data type + uint16_t pkt_len; // packet length +} *cu_head; + + switch(so->so_emu) { + +#ifdef EMULATE_TALK + case EMU_TALK: + case EMU_NTALK: + /* + * Talk emulation. We always change the ctl_addr to get + * some answers from the daemon. When an ANNOUNCE comes, + * we send LEAVE_INVITE to the local daemons. Also when a + * DELETE comes, we send copies to the local daemons. + */ + 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; \ + dest->id_num = src->id_num; \ + dest->pid = src->pid; \ + dest->addr = src->addr; \ + dest->ctl_addr = src->ctl_addr; \ + memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \ + memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \ + memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); } + +#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field) +/* old_sockaddr to sockaddr_in */ + + + if (IS_OLD) { /* old talk */ + omsg = mtod(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 */ + omsg = (CTL_MSG_OLD *) buff; + nmsg = mtod(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) + return; /* for LOOK_UP this is enough */ + + if (IS_OLD) { /* make a copy of the message */ + COPY_MSG(nmsg, omsg); + nmsg->vers = 1; + nmsg->answer = 0; + } else + COPY_MSG(omsg, nmsg); + + /* + * If if is an ANNOUNCE message, we go through the + * request table to see if a tcp port has already + * been redirected for this socket. If not, we solisten() + * a new socket and add this entry to the table. + * The port number of the tcp socket and our IP + * are put to the addr field of the message structures. + * Then a LEAVE_INVITE is sent to both local daemon + * 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, + 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, + (struct sockaddr *) &addr, + &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; + + /* 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; + + 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, + (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; + 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; + addr.sin_port = htons(517); + 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); + + OTOSIN(omsg, ctl_addr)->sin_port = temp_port; + OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; + + /* delete table entry */ + if (so == req_tbl->udp_so) { + temp_req = req_tbl; + req_tbl = req_tbl->next; + free(temp_req); + } else { + temp_req = req_tbl; + for(req = req_tbl->next; req; req = req_next) { + req_next = req->next; + if (so == req->udp_so) { + temp_req->next = req_next; + free(req); + break; + } else { + temp_req = req; + } + } + } + } + + 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->s_port = addr.sin_port; + cu_head->so_addr = our_addr.s_addr; + } + + return; + } +} + +struct SLIRPsocket * +udp_listen(port, laddr, lport, flags) + u_int port; + u_int32_t laddr; + u_int lport; + int flags; +{ + struct sockaddr_in addr; + struct SLIRPsocket *so; + socklen_t addrlen = sizeof(struct sockaddr_in); + int opt = 1; + + if ((so = socreate()) == NULL) { + free(so); + return NULL; + } + so->s = socket(AF_INET,SOCK_DGRAM,0); + so->so_expire = curtime + SO_EXPIRE; + insque(so,&udb); + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = port; + + if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { + 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)); */ + + 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; +} diff --git a/src/slirp/udp.h b/src/slirp/udp.h new file mode 100644 index 000000000..2f6b1e483 --- /dev/null +++ b/src/slirp/udp.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)udp.h 8.1 (Berkeley) 6/10/93 + * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp + */ + +#ifndef _UDP_H_ +#define _UDP_H_ + +#define UDP_TTL 0x60 +#define UDP_UDPDATALEN 16192 + +extern struct SLIRPsocket *udp_last_so; + +/* + * Udp protocol header. + * Per RFC 768, September, 1981. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct udphdr { + u_int16_t uh_sport; /* source port */ + u_int16_t uh_dport; /* destination port */ + int16_t uh_ulen; /* udp length */ + u_int16_t uh_sum; /* udp checksum */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +/* + * UDP kernel structures and variables. + */ +struct udpiphdr { + struct ipovly ui_i; /* overlaid ip structure */ + struct udphdr ui_u; /* udp header */ +}; +#define ui_next ui_i.ih_next +#define ui_prev ui_i.ih_prev +#define ui_x1 ui_i.ih_x1 +#define ui_pr ui_i.ih_pr +#define ui_len ui_i.ih_len +#define ui_src ui_i.ih_src +#define ui_dst ui_i.ih_dst +#define ui_sport ui_u.uh_sport +#define ui_dport ui_u.uh_dport +#define ui_ulen ui_u.uh_ulen +#define ui_sum ui_u.uh_sum + +struct udpstat { + /* input statistics: */ + u_long udps_ipackets; /* total input packets */ + u_long udps_hdrops; /* packet shorter than header */ + u_long udps_badsum; /* checksum error */ + u_long udps_badlen; /* data length larger than packet */ + u_long udps_noport; /* no socket on port */ + u_long udps_noportbcast; /* of above, arrived as broadcast */ + u_long udps_fullsock; /* not delivered, input socket full */ + u_long udpps_pcbcachemiss; /* input packets missing pcb cache */ + /* output statistics: */ + u_long udps_opackets; /* total output packets */ +}; + +/* + * Names for UDP sysctl objects + */ +#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ +#define UDPCTL_MAXID 2 + +extern struct udpstat udpstat; +extern struct SLIRPsocket udb; +struct SLIRPmbuf; + +void udp_init _P((void)); +void udp_input _P((register struct SLIRPmbuf *, int)); +int udp_output _P((struct SLIRPsocket *, struct SLIRPmbuf *, struct sockaddr_in *)); +int udp_attach _P((struct SLIRPsocket *)); +void udp_detach _P((struct SLIRPsocket *)); +u_int8_t udp_tos _P((struct SLIRPsocket *)); +void udp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +struct SLIRPsocket * udp_listen _P((u_int, u_int32_t, u_int, int)); +int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m, + struct sockaddr_in *saddr, struct sockaddr_in *daddr, + int iptos); +#endif diff --git a/src/sound.c b/src/sound.c new file mode 100644 index 000000000..1fedb4c79 --- /dev/null +++ b/src/sound.c @@ -0,0 +1,230 @@ +#include +#include +#include "ibm.h" +#include "device.h" + +#include "filters.h" + +#include "sound_opl.h" + +#include "sound.h" +#include "sound_adlib.h" +#include "sound_adlibgold.h" +#include "sound_pas16.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" +#include "sound_wss.h" + +#include "timer.h" +#include "thread.h" + +int sound_card_current = 0; +static int sound_card_last = 0; + +typedef struct +{ + char name[32]; + device_t *device; +} SOUND_CARD; + +static SOUND_CARD sound_cards[] = +{ + {"None", NULL}, + {"Adlib", &adlib_device}, + {"Sound Blaster 1.0", &sb_1_device}, + {"Sound Blaster 1.5", &sb_15_device}, + {"Sound Blaster 2.0", &sb_2_device}, + {"Sound Blaster Pro v1", &sb_pro_v1_device}, + {"Sound Blaster Pro v2", &sb_pro_v2_device}, + {"Sound Blaster 16", &sb_16_device}, + {"Sound Blaster AWE32", &sb_awe32_device}, + {"Adlib Gold", &adgold_device}, + {"Windows Sound System", &wss_device}, + {"Pro Audio Spectrum 16", &pas16_device}, + {"", NULL} +}; + +int sound_card_available(int card) +{ + if (sound_cards[card].device) + return device_available(sound_cards[card].device); + + return 1; +} + +char *sound_card_getname(int card) +{ + return sound_cards[card].name; +} + +device_t *sound_card_getdevice(int card) +{ + return sound_cards[card].device; +} + +int sound_card_has_config(int card) +{ + if (!sound_cards[card].device) + return 0; + return sound_cards[card].device->config ? 1 : 0; +} + +void sound_card_init() +{ + if (sound_cards[sound_card_current].device) + device_add(sound_cards[sound_card_current].device); + sound_card_last = sound_card_current; +} + +static struct +{ + void (*get_buffer)(int32_t *buffer, int len, void *p); + void *priv; +} sound_handlers[8]; + +static int sound_handlers_num; + +static int sound_poll_time = 0, sound_get_buffer_time = 0, sound_poll_latch; +int sound_pos_global = 0; + +int soundon = 1; + +static int16_t cd_buffer[CD_BUFLEN * 2]; +static thread_t *sound_cd_thread_h; +static event_t *sound_cd_event; +static unsigned int cd_vol_l, cd_vol_r; + +void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) +{ + cd_vol_l = vol_l; + cd_vol_r = vol_r; +} + +static void sound_cd_thread(void *param) +{ + while (1) + { + int c; + + thread_wait_event(sound_cd_event, -1); + ioctl_audio_callback(cd_buffer, CD_BUFLEN*2); + if (soundon) + { + int32_t atapi_vol_l = atapi_get_cd_volume(0); + int32_t atapi_vol_r = atapi_get_cd_volume(1); + int channel_select[2]; + + channel_select[0] = atapi_get_cd_channel(0); + channel_select[1] = atapi_get_cd_channel(1); + + for (c = 0; c < CD_BUFLEN*2; c += 2) + { + int32_t cd_buffer_temp[2] = {0, 0}; + + /*First, adjust input from drive according to ATAPI volume.*/ + cd_buffer[c] = ((int32_t)cd_buffer[c] * atapi_vol_l) / 255; + cd_buffer[c+1] = ((int32_t)cd_buffer[c+1] * atapi_vol_r) / 255; + + /*Apply ATAPI channel select*/ + if (channel_select[0] & 1) + cd_buffer_temp[0] += cd_buffer[c]; + if (channel_select[0] & 2) + cd_buffer_temp[1] += cd_buffer[c]; + if (channel_select[1] & 1) + cd_buffer_temp[0] += cd_buffer[c+1]; + if (channel_select[1] & 2) + cd_buffer_temp[1] += cd_buffer[c+1]; + + /*Apply sound card CD volume*/ + cd_buffer_temp[0] = (cd_buffer_temp[0] * (int)cd_vol_l) / 65535; + cd_buffer_temp[1] = (cd_buffer_temp[1] * (int)cd_vol_r) / 65535; + + if (cd_buffer_temp[0] > 32767) + cd_buffer_temp[0] = 32767; + if (cd_buffer_temp[0] < -32768) + cd_buffer_temp[0] = -32768; + if (cd_buffer_temp[1] > 32767) + cd_buffer_temp[1] = 32767; + if (cd_buffer_temp[1] < -32768) + cd_buffer_temp[1] = -32768; + + cd_buffer[c] = cd_buffer_temp[0]; + cd_buffer[c+1] = cd_buffer_temp[1]; + } + + givealbuffer_cd(cd_buffer); + } + } +} + +static int32_t *outbuffer; + +void sound_init() +{ + initalmain(0,NULL); + inital(); + + outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); + + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); +} + +void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) +{ + sound_handlers[sound_handlers_num].get_buffer = get_buffer; + sound_handlers[sound_handlers_num].priv = p; + sound_handlers_num++; +} + +void sound_poll(void *priv) +{ + sound_poll_time += sound_poll_latch; + + sound_pos_global++; + if (sound_pos_global == SOUNDBUFLEN) + { + int c; +/* int16_t buf16[SOUNDBUFLEN * 2 ];*/ + + memset(outbuffer, 0, SOUNDBUFLEN * 2 * sizeof(int32_t)); + + for (c = 0; c < sound_handlers_num; c++) + sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv); + + +/* for (c=0;c 32767) + buf16[c] = 32767; + else + buf16[c] = outbuffer[c]; + } + + if (!soundf) soundf=fopen("sound.pcm","wb"); + fwrite(buf16,(SOUNDBUFLEN)*2*2,1,soundf);*/ + + if (soundon) givealbuffer(outbuffer); + + thread_set_event(sound_cd_event); + + sound_pos_global = 0; + } +} + +void sound_speed_changed() +{ + sound_poll_latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); +} + +void sound_reset() +{ + timer_add(sound_poll, &sound_poll_time, TIMER_ALWAYS_ENABLED, NULL); + + sound_handlers_num = 0; + + sound_set_cd_volume(65535, 65535); + ioctl_audio_stop(); +} diff --git a/src/sound.h b/src/sound.h new file mode 100644 index 000000000..352d0cf41 --- /dev/null +++ b/src/sound.h @@ -0,0 +1,20 @@ +#include "timer.h" + +void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p); + +extern int sbtype; + +extern int sound_card_current; + +int sound_card_available(int card); +char *sound_card_getname(int card); +struct device_t *sound_card_getdevice(int card); +int sound_card_has_config(int card); +void sound_card_init(); +void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r); + +#define CD_FREQ 44100 +#define CD_BUFLEN (CD_FREQ / 10) + +extern int sound_pos_global; +void sound_speed_changed(); diff --git a/src/sound_ad1848.c b/src/sound_ad1848.c new file mode 100644 index 000000000..9dd339bce --- /dev/null +++ b/src/sound_ad1848.c @@ -0,0 +1,219 @@ +/*PCem v0.8 by Tom Walker + + AD1848 CODEC emulation (Windows Sound System compatible)*/ + +#include "ibm.h" +#include "sound.h" +#include "sound_ad1848.h" + +static int ad1848_vols[64]; + +void ad1848_setirq(ad1848_t *ad1848, int irq) +{ + ad1848->irq = irq; +} + +void ad1848_setdma(ad1848_t *ad1848, int dma) +{ + ad1848->dma = dma; +} + +uint8_t ad1848_read(uint16_t addr, void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + uint8_t temp = 0xff; +// pclog("ad1848_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); + switch (addr & 3) + { + case 0: /*Index*/ + temp = ad1848->index | ad1848->trd | ad1848->mce; + break; + case 1: + temp = ad1848->regs[ad1848->index]; + break; + case 2: + temp = ad1848->status; + break; + } +// pclog("return %02X\n", temp); + return temp; +} + +void ad1848_write(uint16_t addr, uint8_t val, void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + double freq; +// pclog("ad1848_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); + switch (addr & 3) + { + case 0: /*Index*/ + ad1848->index = val & 0xf; + ad1848->trd = val & 0x20; + ad1848->mce = val & 0x40; + break; + case 1: + switch (ad1848->index) + { + case 8: + freq = (val & 1) ? 16934400 : 24576000; + switch ((val >> 1) & 7) + { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + ad1848->freq = freq; + ad1848->timer_latch = (int)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + break; + + case 9: + ad1848->enable = ((val & 0x41) == 0x01); + if (!ad1848->enable) + ad1848->out_l = ad1848->out_r = 0; + break; + + case 12: + return; + + case 14: + ad1848->count = ad1848->regs[15] | (val << 8); + break; + } + ad1848->regs[ad1848->index] = val; + break; + case 2: + ad1848->status &= 0xfe; + break; + } +} + +void ad1848_speed_changed(ad1848_t *ad1848) +{ + ad1848->timer_latch = (int)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); +} + +void ad1848_update(ad1848_t *ad1848) +{ + for (; ad1848->pos < sound_pos_global; ad1848->pos++) + { + ad1848->buffer[ad1848->pos*2] = ad1848->out_l; + ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; + } +} + +static void ad1848_poll(void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + + if (ad1848->timer_latch) + ad1848->timer_count += ad1848->timer_latch; + else + ad1848->timer_count = TIMER_USEC; + + ad1848_update(ad1848); + + if (ad1848->enable) + { + int32_t temp; + + switch (ad1848->regs[8] & 0x70) + { + case 0x00: /*Mono, 8-bit PCM*/ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + case 0x10: /*Stereo, 8-bit PCM*/ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + + case 0x40: /*Mono, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + case 0x50: /*Stereo, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + } + + if (ad1848->regs[6] & 0x80) + ad1848->out_l = 0; + else + ad1848->out_l = (ad1848->out_l * ad1848_vols[ad1848->regs[6] & 0x3f]) >> 16; + + if (ad1848->regs[7] & 0x80) + ad1848->out_r = 0; + else + ad1848->out_r = (ad1848->out_r * ad1848_vols[ad1848->regs[7] & 0x3f]) >> 16; + + if (ad1848->count < 0) + { + ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); + if (!(ad1848->status & 0x01)) + { + ad1848->status |= 0x01; + if (ad1848->regs[0xa] & 2) + picint(1 << ad1848->irq); + } + } + + ad1848->count--; +// pclog("ad1848_poll : enable %X %X %X %X %X %X\n", ad1848->pcm_buffer[0][ad1848->pos], ad1848->pcm_buffer[1][ad1848->pos], ad1848->out_l[0], ad1848->out_r[0], ad1848->out_l[1], ad1848->out_r[1]); + } + else + { + ad1848->out_l = ad1848->out_r = 0; +// pclog("ad1848_poll : not enable\n"); + } +} + +void ad1848_init(ad1848_t *ad1848) +{ + int c; + double attenuation; + + ad1848->enable = 0; + + ad1848->status = 0xcc; + ad1848->index = ad1848->trd = 0; + ad1848->mce = 0x40; + + ad1848->regs[0] = ad1848->regs[1] = 0; + ad1848->regs[2] = ad1848->regs[3] = 0x80; + ad1848->regs[4] = ad1848->regs[5] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; + ad1848->regs[8] = 0; + ad1848->regs[9] = 0x08; + ad1848->regs[10] = ad1848->regs[11] = 0; + ad1848->regs[12] = 0xa; + ad1848->regs[13] = 0; + ad1848->regs[14] = ad1848->regs[15] = 0; + + ad1848->out_l = 0; + ad1848->out_r = 0; + + for (c = 0; c < 64; c++) + { + attenuation = 0.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + if (c & 0x20) attenuation -= 48.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols[c] = (int)(attenuation * 65536); +// pclog("ad1848_vols %i = %f %i\n", c, attenuation, ad1848_vols[c]); + } + + timer_add(ad1848_poll, &ad1848->timer_count, &ad1848->enable, ad1848); +} diff --git a/src/sound_ad1848.h b/src/sound_ad1848.h new file mode 100644 index 000000000..b97e1e499 --- /dev/null +++ b/src/sound_ad1848.h @@ -0,0 +1,35 @@ +#include "timer.h" + +typedef struct ad1848_t +{ + int index; + uint8_t regs[16]; + uint8_t status; + + int trd; + int mce; + + int count; + + int16_t out_l, out_r; + + int enable; + + int irq, dma; + + int freq; + + int timer_count, timer_latch; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} ad1848_t; + +void ad1848_setirq(ad1848_t *ad1848, int irq); +void ad1848_setdma(ad1848_t *ad1848, int dma); + +uint8_t ad1848_read(uint16_t addr, void *p); +void ad1848_write(uint16_t addr, uint8_t val, void *p); + +void ad1848_update(ad1848_t *ad1848); +void ad1848_speed_changed(ad1848_t *ad1848); diff --git a/src/sound_adlib.c b/src/sound_adlib.c new file mode 100644 index 000000000..f4e24bb44 --- /dev/null +++ b/src/sound_adlib.c @@ -0,0 +1,56 @@ +#include +#include "ibm.h" +#include "device.h" +#include "sound.h" + +#include "sound_adlib.h" +#include "sound_opl.h" + +typedef struct adlib_t +{ + opl_t opl; +} adlib_t; + +static void adlib_get_buffer(int32_t *buffer, int len, void *p) +{ + adlib_t *adlib = (adlib_t *)p; + int c; + + opl2_update2(&adlib->opl); + + for (c = 0; c < len * 2; c++) + buffer[c] += (int32_t)adlib->opl.buffer[c]; + + adlib->opl.pos = 0; +} + +void *adlib_init() +{ + adlib_t *adlib = malloc(sizeof(adlib_t)); + memset(adlib, 0, sizeof(adlib_t)); + + pclog("adlib_init\n"); + opl2_init(&adlib->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + sound_add_handler(adlib_get_buffer, adlib); + return adlib; +} + +void adlib_close(void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + free(adlib); +} + +device_t adlib_device = +{ + "AdLib", + 0, + adlib_init, + adlib_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_adlib.h b/src/sound_adlib.h new file mode 100644 index 000000000..c8db01482 --- /dev/null +++ b/src/sound_adlib.h @@ -0,0 +1 @@ +extern device_t adlib_device; diff --git a/src/sound_adlibgold.c b/src/sound_adlibgold.c new file mode 100644 index 000000000..a0f0956a9 --- /dev/null +++ b/src/sound_adlibgold.c @@ -0,0 +1,863 @@ +#include +#include +#include "ibm.h" +#include "device.h" + +#include "sound_opl.h" +#include "sound_ym7128.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "sound.h" +#include "timer.h" + +#include "filters.h" + +typedef struct adgold_t +{ + int adgold_irq_status; + + uint8_t adgold_eeprom[0x19]; + + uint8_t adgold_status; + int adgold_38x_state, adgold_38x_addr; + uint8_t adgold_38x_regs[0x19]; + + int adgold_mma_addr; + uint8_t adgold_mma_regs[2][0xe]; + + int adgold_mma_enable[2]; + uint8_t adgold_mma_fifo[2][256]; + int adgold_mma_fifo_start[2], adgold_mma_fifo_end[2]; + uint8_t adgold_mma_status; + + int16_t adgold_mma_out[2]; + int adgold_mma_intpos[2]; + + int adgold_mma_timer_count; + + struct + { + int timer0_latch, timer0_count; + int timerbase_latch, timerbase_count; + int timer1_latch, timer1_count; + int timer2_latch, timer2_count, timer2_read; + + int voice_count[2], voice_latch[2]; + } adgold_mma; + + opl_t opl; + ym7128_t ym7128; + + int fm_vol_l, fm_vol_r; + int samp_vol_l, samp_vol_r; + int vol_l, vol_r; + int treble, bass; + + int16_t opl_buffer[SOUNDBUFLEN * 2]; + int16_t mma_buffer[2][SOUNDBUFLEN]; + + int pos; + + int surround_enabled; +} adgold_t; + +static int attenuation[0x40]; +static int bass_attenuation[0x10] = +{ + (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.413 * 16384), /*9 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(0 * 16384), /*0 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(1.413 * 16384), /*9 dB*/ + (int)(1.995 * 16384), /*12 dB*/ + (int)(2.819 * 16384), /*15 dB*/ + (int)(2.819 * 16384), + (int)(2.819 * 16384), + (int)(2.819 * 16384), + (int)(2.819 * 16384) +}; + +static int bass_cut[6] = +{ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.178 * 16384), /*-9 dB*/ + (int)(0.251 * 16384), /*-6 dB*/ + (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ +}; + +static int treble_attenuation[0x10] = +{ + (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.413 * 16384), /*9 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(0 * 16384), /*0 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(1.413 * 16384), /*9 dB*/ + (int)(1.995 * 16384), /*12 dB*/ + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.995 * 16384) +}; + +static int treble_cut[6] = +{ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.178 * 16384), /*-9 dB*/ + (int)(0.251 * 16384), /*-6 dB*/ + (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ +}; + +void adgold_timer_poll(); +void adgold_update(adgold_t *adgold); + +void adgold_update_irq_status(adgold_t *adgold) +{ + uint8_t temp = 0xf; + + if (!(adgold->adgold_mma_regs[0][8] & 0x10) && (adgold->adgold_mma_status & 0x10)) /*Timer 0*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x20) && (adgold->adgold_mma_status & 0x20)) /*Timer 1*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x40) && (adgold->adgold_mma_status & 0x40)) /*Timer 2*/ + temp &= ~2; + + if ((adgold->adgold_mma_status & 0x01) && !(adgold->adgold_mma_regs[0][0xc] & 2)) + temp &= ~2; + if ((adgold->adgold_mma_status & 0x02) && !(adgold->adgold_mma_regs[1][0xc] & 2)) + temp &= ~2; + adgold->adgold_status = temp; + + if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) + { +// pclog("adgold irq %02X\n", adgold->adgold_status); + picint(0x80); + } + + adgold->adgold_irq_status = adgold->adgold_status ^ 0xf; +} + +void adgold_getsamp_dma(adgold_t *adgold, int channel) +{ + int temp; + + if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127)) + return; + + temp = dma_channel_read(1); +// pclog("adgold DMA1 return %02X %i L\n", temp, channel); + if (temp == DMA_NODATA) return; + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + if (adgold->adgold_mma_regs[channel][0xc] & 0x60) + { + temp = dma_channel_read(1); +// pclog("adgold DMA1 return %02X %i H\n", temp, channel); + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + } + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= adgold->adgold_mma_intpos[channel]) + { + adgold->adgold_mma_status &= ~(0x01 << channel); + adgold_update_irq_status(adgold); + } +} + +void adgold_write(uint16_t addr, uint8_t val, void *p) +{ + adgold_t *adgold = (adgold_t *)p; +// if (addr > 0x389) pclog("adgold_write : addr %04X val %02X %04X:%04X\n", addr, val, CS, pc); + switch (addr & 7) + { + case 0: case 1: + opl3_write(addr, val, &adgold->opl); + break; + + case 2: + if (val == 0xff) + { + adgold->adgold_38x_state = 1; + return; + } + if (val == 0xfe) + { + adgold->adgold_38x_state = 0; + return; + } + if (adgold->adgold_38x_state) /*Write to control chip*/ + adgold->adgold_38x_addr = val; + else + opl3_write(addr, val, &adgold->opl); + break; + case 3: + if (adgold->adgold_38x_state) + { + if (adgold->adgold_38x_addr >= 0x19) break; + switch (adgold->adgold_38x_addr) + { + case 0x00: /*Control/ID*/ + if (val & 1) + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + if (val & 2) + memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x19); + break; + + case 0x04: /*Final output volume left*/ + adgold->adgold_38x_regs[0x04] = val; + adgold->vol_l = attenuation[val & 0x3f]; + break; + case 0x05: /*Final output volume right*/ + adgold->adgold_38x_regs[0x05] = val; + adgold->vol_r = attenuation[val & 0x3f]; + break; + case 0x06: /*Bass*/ + adgold->adgold_38x_regs[0x06] = val; + adgold->bass = val & 0xf; + break; + case 0x07: /*Treble*/ + adgold->adgold_38x_regs[0x07] = val; + adgold->treble = val & 0xf; + break; + + case 0x09: /*FM volume left*/ + adgold->adgold_38x_regs[0x09] = val; + adgold->fm_vol_l = (int)(int8_t)(val - 128); + break; + case 0x0a: /*FM volume right*/ + adgold->adgold_38x_regs[0x0a] = val; + adgold->fm_vol_r = (int)(int8_t)(val - 128); + break; + case 0x0b: /*Sample volume left*/ + adgold->adgold_38x_regs[0x0b] = val; + adgold->samp_vol_l = (int)(int8_t)(val - 128); + break; + case 0x0c: /*Sample volume right*/ + adgold->adgold_38x_regs[0x0c] = val; + adgold->samp_vol_r = (int)(int8_t)(val - 128); + break; + + case 0x18: /*Surround*/ + adgold->adgold_38x_regs[0x18] = val; + ym7128_write(&adgold->ym7128, val); + break; + + default: + adgold->adgold_38x_regs[adgold->adgold_38x_addr] = val; + break; + } + } + else + opl3_write(addr, val, &adgold->opl); + break; + case 4: case 6: + adgold->adgold_mma_addr = val; + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) break; + switch (adgold->adgold_mma_addr) + { + case 0x2: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff00) | val; + break; + case 0x3: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff) | (val << 8); + break; + case 0x4: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xf00) | val; + break; + case 0x5: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xff) | ((val & 0xf) << 8); + adgold->adgold_mma.timer1_latch = val >> 4; + break; + case 0x6: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff00) | val; + break; + case 0x7: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff) | (val << 8); + break; + + case 0x8: + if ((val & 1) && !(adgold->adgold_mma_regs[0][8] & 1)) /*Reload timer 0*/ + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; + + if ((val & 2) && !(adgold->adgold_mma_regs[0][8] & 2)) /*Reload timer 1*/ + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; + + if ((val & 4) && !(adgold->adgold_mma_regs[0][8] & 4)) /*Reload timer 2*/ + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + + if ((val & 8) && !(adgold->adgold_mma_regs[0][8] & 8)) /*Reload base timer*/ + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + break; + + case 0x9: + switch (val & 0x18) + { + case 0x00: adgold->adgold_mma.voice_latch[0] = 12; break; /*44100 Hz*/ + case 0x08: adgold->adgold_mma.voice_latch[0] = 24; break; /*22050 Hz*/ + case 0x10: adgold->adgold_mma.voice_latch[0] = 48; break; /*11025 Hz*/ + case 0x18: adgold->adgold_mma.voice_latch[0] = 72; break; /* 7350 Hz*/ + } + if (val & 0x80) + { + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_end[0] = adgold->adgold_mma_fifo_start[0] = 0; + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[0][0x9] & 1)) + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + +// pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255, adgold->adgold_mma_fifo_end[0], adgold->adgold_mma_fifo_start[0], adgold->adgold_mma_regs[0][0xc]); + if (adgold->adgold_mma_regs[0][0xc] & 1) + { + if (adgold->adgold_mma_regs[0][0xc] & 0x80) + { +// pclog("adgold start interleaved %i %i + adgold->adgold_mma_enable[1] = 1; + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 0); + adgold_getsamp_dma(adgold, 1); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) + { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + } + else + { + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 0); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + } + } +// pclog("adgold end\n"); + } + adgold->adgold_mma_enable[0] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold->adgold_mma_fifo[0][adgold->adgold_mma_fifo_end[0]] = val; + adgold->adgold_mma_fifo_end[0] = (adgold->adgold_mma_fifo_end[0] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[0] = (7 - ((val >> 2) & 7)) * 8; + break; + } + adgold->adgold_mma_regs[0][adgold->adgold_mma_addr] = val; + break; + case 7: + if (adgold->adgold_mma_addr >= 0xf) break; + switch (adgold->adgold_mma_addr) + { + case 0x9: + adgold_update(adgold); + switch (val & 0x18) + { + case 0x00: adgold->adgold_mma.voice_latch[1] = 12; break; /*44100 Hz*/ + case 0x08: adgold->adgold_mma.voice_latch[1] = 24; break; /*22050 Hz*/ + case 0x10: adgold->adgold_mma.voice_latch[1] = 48; break; /*11025 Hz*/ + case 0x18: adgold->adgold_mma.voice_latch[1] = 72; break; /* 7350 Hz*/ + } + if (val & 0x80) + { + adgold->adgold_mma_enable[1] = 0; + adgold->adgold_mma_fifo_end[1] = adgold->adgold_mma_fifo_start[1] = 0; + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[1][0x9] & 1)) + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + +// pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255, adgold->adgold_mma_fifo_end[1], adgold->adgold_mma_fifo_start[1], adgold->adgold_mma_regs[1][0xc]); + if (adgold->adgold_mma_regs[1][0xc] & 1) + { + while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 1); + } + } +// pclog("adgold end\n"); + } + adgold->adgold_mma_enable[1] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) + { + adgold->adgold_mma_fifo[1][adgold->adgold_mma_fifo_end[1]] = val; + adgold->adgold_mma_fifo_end[1] = (adgold->adgold_mma_fifo_end[1] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) + { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[1] = (7 - ((val >> 2) & 7)) * 8; + break; + } + adgold->adgold_mma_regs[1][adgold->adgold_mma_addr] = val; + break; + } +} + +uint8_t adgold_read(uint16_t addr, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + uint8_t temp; + + switch (addr & 7) + { + case 0: case 1: + temp = opl3_read(addr, &adgold->opl); + break; + + case 2: + if (adgold->adgold_38x_state) /*Read from control chip*/ + temp = adgold->adgold_status; + else + temp = opl3_read(addr, &adgold->opl); + break; + + case 3: + if (adgold->adgold_38x_state) + { + if (adgold->adgold_38x_addr >= 0x19) temp = 0xff; + switch (adgold->adgold_38x_addr) + { + case 0x00: /*Control/ID*/ + if (adgold->surround_enabled) + temp = 0x50; /*16-bit ISA, surround module, no telephone/CDROM*/ + else + temp = 0x70; /*16-bit ISA, no telephone/surround/CD-ROM*/ + break; + + default: + temp = adgold->adgold_38x_regs[adgold->adgold_38x_addr]; + } + } + else + temp = opl3_read(addr, &adgold->opl); + break; + + case 4: case 6: + temp = adgold->adgold_mma_status; + adgold->adgold_mma_status = 0; /*JUKEGOLD expects timer status flags to auto-clear*/ + adgold_update_irq_status(adgold); + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; + switch (adgold->adgold_mma_addr) + { + case 6: /*Timer 2 low*/ + adgold->adgold_mma.timer2_read = adgold->adgold_mma.timer2_count; + temp = adgold->adgold_mma.timer2_read & 0xff; + break; + case 7: /*Timer 2 high*/ + temp = adgold->adgold_mma.timer2_read >> 8; + break; + + default: + temp = adgold->adgold_mma_regs[0][adgold->adgold_mma_addr]; + break; + } + break; + case 7: + if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; + temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; + break; + } +// if (addr > 0x389) pclog("adgold_read : addr %04X %02X\n", addr, temp); + return temp; +} + +void adgold_update(adgold_t *adgold) +{ + for (; adgold->pos < sound_pos_global; adgold->pos++) + { + adgold->mma_buffer[0][adgold->pos] = adgold->mma_buffer[1][adgold->pos] = 0; + + if (adgold->adgold_mma_regs[0][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[0] / 2; + if (adgold->adgold_mma_regs[0][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[0] / 2; + + if (adgold->adgold_mma_regs[1][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[1] / 2; + if (adgold->adgold_mma_regs[1][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[1] / 2; + } +} + +void adgold_mma_poll(adgold_t *adgold, int channel) +{ + int16_t dat; + + adgold_update(adgold); + + if (adgold->adgold_mma_fifo_start[channel] != adgold->adgold_mma_fifo_end[channel]) + { + switch (adgold->adgold_mma_regs[channel][0xc] & 0x60) + { + case 0x00: /*8-bit*/ + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] * 256; + adgold->adgold_mma_out[channel] = dat; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + break; + + case 0x40: /*12-bit sensible format*/ + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < 2) + return; + + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] & 0xf0; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + dat |= (adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] << 8); + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + adgold->adgold_mma_out[channel] = dat; + break; + } + + if (adgold->adgold_mma_regs[channel][0xc] & 1) + { + adgold_getsamp_dma(adgold, channel); + } + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01)) + { +// pclog("adgold_mma_poll - IRQ! %i\n", channel); + adgold->adgold_mma_status |= 1 << channel; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_fifo_start[channel] == adgold->adgold_mma_fifo_end[channel]) + { + adgold->adgold_mma_enable[channel] = 0; + } +} + +void adgold_timer_poll(void *p) +{ + adgold_t *adgold = (adgold_t *)p; + + while (adgold->adgold_mma_timer_count <= 0) + { + adgold->adgold_mma_timer_count += (int)((double)TIMER_USEC * 1.88964); + if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ + { + adgold->adgold_mma.timer0_count--; + if (!adgold->adgold_mma.timer0_count) + { + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; +// pclog("Timer 0 interrupt\n"); + adgold->adgold_mma_status |= 0x10; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ + { + adgold->adgold_mma.timerbase_count--; + if (!adgold->adgold_mma.timerbase_count) + { + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ + { + adgold->adgold_mma.timer1_count--; + if (!adgold->adgold_mma.timer1_count) + { + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; +// pclog("Timer 1 interrupt\n"); + adgold->adgold_mma_status |= 0x20; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ + { + adgold->adgold_mma.timer2_count--; + if (!adgold->adgold_mma.timer2_count) + { + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; +// pclog("Timer 2 interrupt\n"); + adgold->adgold_mma_status |= 0x40; + adgold_update_irq_status(adgold); + } + } + } + } + + if (adgold->adgold_mma_enable[0]) + { + adgold->adgold_mma.voice_count[0]--; + if (!adgold->adgold_mma.voice_count[0]) + { + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + adgold_mma_poll(adgold, 0); + } + } + if (adgold->adgold_mma_enable[1]) + { + adgold->adgold_mma.voice_count[1]--; + if (!adgold->adgold_mma.voice_count[1]) + { + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + adgold_mma_poll(adgold, 1); + } + } + } +} + +static void adgold_get_buffer(int32_t *buffer, int len, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + int16_t adgold_buffer[len*2]; + + int c; + + opl3_update2(&adgold->opl); + adgold_update(adgold); + + for (c = 0; c < len * 2; c += 2) + { + adgold_buffer[c] = ((adgold->opl.buffer[c] * adgold->fm_vol_l) >> 7) / 2; + adgold_buffer[c] += ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; + adgold_buffer[c+1] = ((adgold->opl.buffer[c+1] * adgold->fm_vol_r) >> 7) / 2; + adgold_buffer[c+1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; + } + + if (adgold->surround_enabled) + ym7128_apply(&adgold->ym7128, adgold_buffer, len); + + switch (adgold->adgold_38x_regs[0x8] & 6) + { + case 0: + for (c = 0; c < len * 2; c++) + adgold_buffer[c] = 0; + break; + case 2: /*Left channel only*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c+1] = adgold_buffer[c]; + break; + case 4: /*Right channel only*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] = adgold_buffer[c+1]; + break; + case 6: /*Left and right channels*/ + break; + } + + switch (adgold->adgold_38x_regs[0x8] & 0x18) + { + case 0x00: /*Forced mono*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] = adgold_buffer[c+1] = ((int32_t)adgold_buffer[c] + (int32_t)adgold_buffer[c+1]) / 2; + break; + case 0x08: /*Linear stereo*/ + break; + case 0x10: /*Pseudo stereo*/ + /*Filter left channel, leave right channel unchanged*/ + /*Filter cutoff is largely a guess*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]); + break; + case 0x18: /*Spatial stereo*/ + /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet + and a very vague understanding of how op-amps work to go on*/ + for (c = 0; c < len * 2; c += 2) + { + int16_t l = adgold_buffer[c]; + int16_t r = adgold_buffer[c+1]; + + adgold_buffer[c] += (r / 3) + ((l * 2) / 3); + adgold_buffer[c+1] += (l / 3) + ((r * 2) / 3); + } + break; + } + + for (c = 0; c < len * 2; c += 2) + { + int32_t temp, lowpass, highpass; + + /*Output is deliberately halved to avoid clipping*/ + temp = ((int32_t)adgold_buffer[c] * adgold->vol_l) >> 17; + lowpass = adgold_lowpass_iir(0, temp); + highpass = adgold_highpass_iir(0, temp); + if (adgold->bass > 6) + temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; + else if (adgold->bass < 6) + temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); + if (adgold->treble > 6) + temp += (highpass * treble_attenuation[adgold->treble]) >> 14; + else if (adgold->treble < 6) + temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); + if (temp < -32768) + temp = -32768; + if (temp > 32767) + temp = 32767; + buffer[c] += temp; + + temp = ((int32_t)adgold_buffer[c+1] * adgold->vol_r) >> 17; + lowpass = adgold_lowpass_iir(1, temp); + highpass = adgold_highpass_iir(1, temp); + if (adgold->bass > 6) + temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; + else if (adgold->bass < 6) + temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); + if (adgold->treble > 6) + temp += (highpass * treble_attenuation[adgold->treble]) >> 14; + else if (adgold->treble < 6) + temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); + if (temp < -32768) + temp = -32768; + if (temp > 32767) + temp = 32767; + buffer[c+1] += temp; + } + + adgold->opl.pos = 0; + adgold->pos = 0; +} + + +void *adgold_init() +{ + FILE *f; + int c; + double out; + adgold_t *adgold = malloc(sizeof(adgold_t)); + memset(adgold, 0, sizeof(adgold_t)); + + adgold->surround_enabled = device_get_config_int("surround"); + + opl3_init(&adgold->opl); + if (adgold->surround_enabled) + ym7128_init(&adgold->ym7128); + + out = 65536.0; /*Main volume control ranges from +6 dB to -64 dB in 2 dB steps, then remaining settings are -80 dB (effectively 0)*/ + for (c = 0x3f; c >= 0x1c; c--) + { + attenuation[c] = (int)out; + out /= 1.25963; /*2 dB steps*/ + } + for (; c >= 0; c--) + attenuation[c] = 0; + + f = romfopen("nvr/adgold.bin", "rb"); + if (f) + { + fread(adgold->adgold_eeprom, 0x18, 1, f); + fclose(f); + } + + adgold->adgold_status = 0xf; + adgold->adgold_38x_addr = 0; + adgold->adgold_eeprom[0x13] = 3 | (1 << 4); /*IRQ 7, DMA 1*/ + adgold->adgold_eeprom[0x14] = 3 << 4; /*DMA 3*/ + adgold->adgold_eeprom[0x15] = 0x388 / 8; /*Present at 388-38f*/ + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + adgold->vol_l = attenuation[adgold->adgold_eeprom[0x04] & 0x3f]; + adgold->vol_r = attenuation[adgold->adgold_eeprom[0x05] & 0x3f]; + adgold->bass = adgold->adgold_eeprom[0x06] & 0xf; + adgold->treble = adgold->adgold_eeprom[0x07] & 0xf; + adgold->fm_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x09] - 128); + adgold->fm_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0a] - 128); + adgold->samp_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x0b] - 128); + adgold->samp_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0c] - 128); + + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_start[0] = adgold->adgold_mma_fifo_end[0] = 0; + + /*388/389 are handled by adlib_init*/ + io_sethandler(0x0388, 0x0008, adgold_read, NULL, NULL, adgold_write, NULL, NULL, adgold); + + timer_add(adgold_timer_poll, &adgold->adgold_mma_timer_count, TIMER_ALWAYS_ENABLED, adgold); + + sound_add_handler(adgold_get_buffer, adgold); + + return adgold; +} + +void adgold_close(void *p) +{ + FILE *f; + adgold_t *adgold = (adgold_t *)p; + + f = romfopen("nvr/adgold.bin", "wb"); + if (f) + { + fwrite(adgold->adgold_eeprom, 0x18, 1, f); + fclose(f); + } + + free(adgold); +} + +static device_config_t adgold_config[] = +{ + { + .name = "surround", + .description = "Surround module", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = -1 + } +}; + +device_t adgold_device = +{ + "AdLib Gold", + 0, + adgold_init, + adgold_close, + NULL, + NULL, + NULL, + NULL, + adgold_config +}; diff --git a/src/sound_adlibgold.h b/src/sound_adlibgold.h new file mode 100644 index 000000000..b952aaf03 --- /dev/null +++ b/src/sound_adlibgold.h @@ -0,0 +1 @@ +extern device_t adgold_device; diff --git a/src/sound_cms.c b/src/sound_cms.c new file mode 100644 index 000000000..f38f46f9c --- /dev/null +++ b/src/sound_cms.c @@ -0,0 +1,183 @@ +#include +#include +#include "ibm.h" + +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_cms.h" + +typedef struct cms_t +{ + int addrs[2]; + uint8_t regs[2][32]; + uint16_t latch[2][6]; + int freq[2][6]; + float count[2][6]; + int vol[2][6][2]; + int stat[2][6]; + uint16_t noise[2][2]; + uint16_t noisefreq[2][2]; + int noisecount[2][2]; + int noisetype[2][2]; + + int16_t buffer[SOUNDBUFLEN * 2]; + + int pos; +} cms_t; + +void cms_update(cms_t *cms) +{ + for (; cms->pos < sound_pos_global; cms->pos++) + { + int c, d; + int16_t out_l = 0, out_r = 0; + + for (c = 0; c < 4; c++) + { + switch (cms->noisetype[c >> 1][c & 1]) + { + case 0: cms->noisefreq[c >> 1][c & 1] = 31250; break; + case 1: cms->noisefreq[c >> 1][c & 1] = 15625; break; + case 2: cms->noisefreq[c >> 1][c & 1] = 7812; break; + case 3: cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; break; + } + } + for (c = 0; c < 2; c ++) + { + if (cms->regs[c][0x1C] & 1) + { + for (d = 0; d < 6; d++) + { + if (cms->regs[c][0x14] & (1 << d)) + { + if (cms->stat[c][d]) out_l += (cms->vol[c][d][0] * 90); + if (cms->stat[c][d]) out_r += (cms->vol[c][d][1] * 90); + cms->count[c][d] += cms->freq[c][d]; + if (cms->count[c][d] >= 24000) + { + cms->count[c][d] -= 24000; + cms->stat[c][d] ^= 1; + } + } + else if (cms->regs[c][0x15] & (1 << d)) + { + if (cms->noise[c][d / 3] & 1) out_l += (cms->vol[c][d][0] * 90); + if (cms->noise[c][d / 3] & 1) out_r += (cms->vol[c][d][0] * 90); + } + } + for (d = 0; d < 2; d++) + { + cms->noisecount[c][d] += cms->noisefreq[c][d]; + while (cms->noisecount[c][d] >= 24000) + { + cms->noisecount[c][d] -= 24000; + cms->noise[c][d] <<= 1; + if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40))) + cms->noise[c][d] |= 1; + } + } + } + } + cms->buffer[(cms->pos << 1)] = out_l; + cms->buffer[(cms->pos << 1) + 1] = out_r; + } +} + +void cms_get_buffer(int32_t *buffer, int len, void *p) +{ + cms_t *cms = (cms_t *)p; + + int c; + + cms_update(cms); + + for (c = 0; c < len * 2; c++) + buffer[c] += cms->buffer[c]; + + cms->pos = 0; +} + +void cms_write(uint16_t addr, uint8_t val, void *p) +{ + cms_t *cms = (cms_t *)p; + int voice; + int chip = (addr & 2) >> 1; + + pclog("cms_write : addr %04X val %02X\n", addr, val); + + if (addr & 1) + cms->addrs[chip] = val & 31; + else + { + cms_update(cms); + cms->regs[chip][cms->addrs[chip] & 31] = val; + switch (cms->addrs[chip] & 31) + { + case 0x00: case 0x01: case 0x02: /*Volume*/ + case 0x03: case 0x04: case 0x05: + voice = cms->addrs[chip] & 7; + cms->vol[chip][voice][0] = val & 0xf; + cms->vol[chip][voice][1] = val >> 4; + break; + case 0x08: case 0x09: case 0x0A: /*Frequency*/ + case 0x0B: case 0x0C: case 0x0D: + voice = cms->addrs[chip] & 7; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; + cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + break; + case 0x10: case 0x11: case 0x12: /*Octave*/ + voice = (cms->addrs[chip] & 3) << 1; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); + cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); + cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + cms->freq[chip][voice + 1] = (15625 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); + break; + case 0x16: /*Noise*/ + cms->noisetype[chip][0] = val & 3; + cms->noisetype[chip][1] = (val >> 4) & 3; + break; + } + } +} + +uint8_t cms_read(uint16_t addr, void *p) +{ + cms_t *cms = (cms_t *)p; + int chip = (addr & 2) >> 1; + + if (addr & 1) + return cms->addrs[chip]; + + return cms->regs[chip][cms->addrs[chip] & 31]; +} + +void *cms_init() +{ + cms_t *cms = malloc(sizeof(cms_t)); + memset(cms, 0, sizeof(cms_t)); + + pclog("cms_init\n"); + io_sethandler(0x0220, 0x0004, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); + sound_add_handler(cms_get_buffer, cms); + return cms; +} + +void cms_close(void *p) +{ + cms_t *cms = (cms_t *)p; + + free(cms); +} + +device_t cms_device = +{ + "Creative Music System / Game Blaster", + 0, + cms_init, + cms_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_cms.h b/src/sound_cms.h new file mode 100644 index 000000000..d5795cc0f --- /dev/null +++ b/src/sound_cms.h @@ -0,0 +1 @@ +extern device_t cms_device; diff --git a/src/sound_dbopl.cc b/src/sound_dbopl.cc new file mode 100644 index 000000000..111618dcb --- /dev/null +++ b/src/sound_dbopl.cc @@ -0,0 +1,141 @@ +#include "dosbox/dbopl.h" +#include "sound_dbopl.h" + +static struct +{ + DBOPL::Chip chip; + int addr; + int timer[2]; + uint8_t timer_ctrl; + uint8_t status_mask; + uint8_t status; + int is_opl3; + + void (*timer_callback)(void *param, int timer, int64_t period); + void *timer_param; +} opl[2]; + +enum +{ + STATUS_TIMER_1 = 0x40, + STATUS_TIMER_2 = 0x20, + STATUS_TIMER_ALL = 0x80 +}; + +enum +{ + CTRL_IRQ_RESET = 0x80, + CTRL_TIMER1_MASK = 0x40, + CTRL_TIMER2_MASK = 0x20, + CTRL_TIMER2_CTRL = 0x02, + CTRL_TIMER1_CTRL = 0x01 +}; + +void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3) +{ + DBOPL::InitTables(); + opl[nr].chip.Setup(48000, is_opl3); + opl[nr].timer_callback = timer_callback; + opl[nr].timer_param = timer_param; + opl[nr].is_opl3 = is_opl3; +} + +void opl_status_update(int nr) +{ + if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask) + opl[nr].status |= STATUS_TIMER_ALL; + else + opl[nr].status &= ~STATUS_TIMER_ALL; +} + +void opl_timer_over(int nr, int timer) +{ + if (!timer) + { + opl[nr].status |= STATUS_TIMER_1; + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + } + else + { + opl[nr].status |= STATUS_TIMER_2; + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + } + + opl_status_update(nr); +} + +void opl_write(int nr, uint16_t addr, uint8_t val) +{ + if (!(addr & 1)) + opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & (opl[nr].is_opl3 ? 0x1ff : 0xff); + else + { + opl[nr].chip.WriteReg(opl[nr].addr, val); + + switch (opl[nr].addr) + { + case 0x02: /*Timer 1*/ + opl[nr].timer[0] = 256 - val; + break; + case 0x03: /*Timer 2*/ + opl[nr].timer[1] = 256 - val; + break; + case 0x04: /*Timer control*/ + if (val & CTRL_IRQ_RESET) /*IRQ reset*/ + { + opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); + opl_status_update(nr); + return; + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL) + { + if (val & CTRL_TIMER1_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + else + opl[nr].timer_callback(opl[nr].timer_param, 0, 0); + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL) + { + if (val & CTRL_TIMER2_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + else + opl[nr].timer_callback(opl[nr].timer_param, 1, 0); + } + opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; + opl[nr].timer_ctrl = val; + break; + } + } + +} + +uint8_t opl_read(int nr, uint16_t addr) +{ + if (!(addr & 1)) + { + return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06); + } + return opl[nr].is_opl3 ? 0 : 0xff; +} + +void opl2_update(int nr, int16_t *buffer, int samples) +{ + int c; + Bit32s buffer_32[samples]; + + opl[nr].chip.GenerateBlock2(samples, buffer_32); + + for (c = 0; c < samples; c++) + buffer[c*2] = (int16_t)buffer_32[c]; +} + +void opl3_update(int nr, int16_t *buffer, int samples) +{ + int c; + Bit32s buffer_32[samples*2]; + + opl[nr].chip.GenerateBlock3(samples, buffer_32); + + for (c = 0; c < samples*2; c++) + buffer[c] = (int16_t)buffer_32[c]; +} diff --git a/src/sound_dbopl.h b/src/sound_dbopl.h new file mode 100644 index 000000000..450c5dca3 --- /dev/null +++ b/src/sound_dbopl.h @@ -0,0 +1,12 @@ +#ifdef __cplusplus +extern "C" { +#endif + void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3); + void opl_write(int nr, uint16_t addr, uint8_t val); + uint8_t opl_read(int nr, uint16_t addr); + void opl_timer_over(int nr, int timer); + void opl2_update(int nr, int16_t *buffer, int samples); + void opl3_update(int nr, int16_t *buffer, int samples); +#ifdef __cplusplus +} +#endif diff --git a/src/sound_emu8k.c b/src/sound_emu8k.c new file mode 100644 index 000000000..6274b8839 --- /dev/null +++ b/src/sound_emu8k.c @@ -0,0 +1,754 @@ +/*12log2(r) * 4096 + + freq = 2^((in - 0xe000) / 4096)*/ +/*LFO - lowest (0.042 Hz) = 2^20 steps = 1048576 + highest (10.72 Hz) = 2^12 steps = 4096*/ +#include +#include +#include "ibm.h" +#include "device.h" +#include "sound.h" +#include "sound_emu8k.h" +#include "timer.h" + +enum +{ + ENV_STOPPED = 0, + ENV_ATTACK = 1, + ENV_DECAY = 2, + ENV_SUSTAIN = 3, + ENV_RELEASE = 4 +}; + +static int64_t freqtable[65536]; +static int attentable[256]; +static int envtable[4096]; +static int lfotable[4096]; + +static int32_t filt_w0[256]; +/*static float filt_w0[256];*/ + +#define READ16(addr, var) switch ((addr) & 2) \ + { \ + case 0: ret = (var) & 0xffff; break; \ + case 2: ret = ((var) >> 16) & 0xffff; break; \ + } + +#define WRITE16(addr, var, val) switch ((addr) & 2) \ + { \ + case 0: var = (var & 0xffff0000) | (val); break; \ + case 2: var = (var & 0x0000ffff) | ((val) << 16); break; \ + } + +static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr) +{ + addr &= 0xffffff; + if (addr < 0x80000) + return emu8k->rom[addr]; + if (addr < 0x200000 || addr >= emu8k->ram_end_addr) + return 0; + if (!emu8k->ram) + return 0; + return emu8k->ram[addr - 0x200000]; +} + +static inline int16_t EMU8K_READ_INTERP(emu8k_t *emu8k, uint32_t addr) +{ + int16_t dat1 = EMU8K_READ(emu8k, addr >> 8); + int16_t dat2 = EMU8K_READ(emu8k, (addr >> 8) + 1); + return ((dat1 * (0xff - (addr & 0xff))) + (dat2 * (addr & 0xff))) >> 8; +} + +static inline void EMU8K_WRITE(emu8k_t *emu8k, uint32_t addr, uint16_t val) +{ + addr &= 0xffffff; + if (emu8k->ram && addr >= 0x200000 && addr < emu8k->ram_end_addr) + emu8k->ram[addr - 0x200000] = val; +} +static int ff = 0; +static int voice_count = 0; + +uint16_t emu8k_inw(uint32_t addr, void *p) +{ + emu8k_t *emu8k = (emu8k_t *)p; + uint16_t ret; +/* pclog("emu8k_inw %04X reg=%i voice=%i\n", addr, emu8k->cur_reg, emu8k->cur_voice);*/ + + addr -= 0x220; + switch (addr & 0xc02) + { + case 0x400: case 0x402: /*Data0*/ + switch (emu8k->cur_reg) + { + case 0: + READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); + return ret; + + case 1: + READ16(addr, emu8k->voice[emu8k->cur_voice].ptrx); + return ret; + + case 2: + READ16(addr, emu8k->voice[emu8k->cur_voice].cvcf); + return ret; + + case 3: + READ16(addr, emu8k->voice[emu8k->cur_voice].vtft); + return ret; + + case 4: case 5: /*???*/ + return 0xffff; + + case 6: + READ16(addr, emu8k->voice[emu8k->cur_voice].psst); + return ret; + + case 7: + READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); + return ret; + } + break; + + case 0x800: /*Data1*/ + switch (emu8k->cur_reg) + { + case 0: + { + uint32_t val = (emu8k->voice[emu8k->cur_voice].ccca & 0xff000000) | (emu8k->voice[emu8k->cur_voice].addr >> 8); + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; + } + + case 1: + switch (emu8k->cur_voice) + { + case 20: + READ16(addr, emu8k->smalr); + return ret; + case 21: + READ16(addr, emu8k->smarr); + return ret; + case 22: + READ16(addr, emu8k->smalw); + return ret; + case 23: + READ16(addr, emu8k->smarw); + return ret; + + case 26: + { + uint16_t val = emu8k->smld_buffer; + emu8k->smld_buffer = EMU8K_READ(emu8k, emu8k->smalr); +/* pclog("emu8k_SMLR in %04X (%04X) %08X\n", val, emu8k->smld_buffer, emu8k->smalr);*/ + emu8k->smalr++; + return val; + } + /*The EMU8000 PGM describes the return values of these registers as 'a VLSI error'*/ + case 29: /*Configuration Word 1*/ + return (emu8k->hwcf1 & 0xfe) | (emu8k->hwcf3 & 0x01); + case 30: /*Configuration Word 2*/ + return ((emu8k->hwcf2 >> 4) & 0x0e) | (emu8k->hwcf1 & 0x01) | ((emu8k->hwcf3 & 0x02) ? 0x10 : 0) | ((emu8k->hwcf3 & 0x04) ? 0x40 : 0) | ((emu8k->hwcf3 & 0x08) ? 0x20 : 0) | ((emu8k->hwcf3 & 0x10) ? 0x80 : 0); + case 31: /*Configuration Word 3*/ + return emu8k->hwcf2 & 0x1f; + } + break; + + case 2: /*INIT1*/ + case 3: /*INIT3*/ + return 0xffff; /*Can we read anything useful from here?*/ + + case 5: + return emu8k->voice[emu8k->cur_voice].dcysusv; + + case 7: + return emu8k->voice[emu8k->cur_voice].dcysus; + } + break; + + case 0x802: /*Data2*/ + switch (emu8k->cur_reg) + { + case 0: + { + uint32_t val = (emu8k->voice[emu8k->cur_voice].ccca & 0xff000000) | (emu8k->voice[emu8k->cur_voice].addr >> 8); + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; + } + + case 1: + switch (emu8k->cur_voice) + { + case 20: + READ16(addr, emu8k->smalr | ff); + ff ^= 0x80000000; + return ret; + case 21: + READ16(addr, emu8k->smarr | ff); + ff ^= 0x80000000; + return ret; + case 22: + READ16(addr, emu8k->smalw); + return ret; + case 23: + READ16(addr, emu8k->smarw); + return ret; + + case 26: + { + uint16_t val = emu8k->smrd_buffer; + emu8k->smrd_buffer = EMU8K_READ(emu8k, emu8k->smarr); +/* pclog("emu8k_SMRR in %04X (%04X) %08X\n", val, emu8k->smrd_buffer, emu8k->smarr);*/ + emu8k->smarr++; + return val; + } + + case 27: /*Sample Counter*/ + return emu8k->wc; + } + break; + + case 2: /*INIT2*/ + case 3: /*INIT4*/ + return 0xffff; /*Can we read anything useful from here?*/ + + case 4: + return emu8k->voice[emu8k->cur_voice].atkhldv; + } + break; + + case 0xc00: /*Data3*/ + switch (emu8k->cur_reg) + { + case 0: + return emu8k->voice[emu8k->cur_voice].ip; + + case 1: + return emu8k->voice[emu8k->cur_voice].ifatn; + + case 2: + return emu8k->voice[emu8k->cur_voice].pefe; + + case 3: + return emu8k->voice[emu8k->cur_voice].fmmod; + + case 4: + return emu8k->voice[emu8k->cur_voice].tremfrq; + + case 5: + return emu8k->voice[emu8k->cur_voice].fm2frq2; + + case 6: + return 0xffff; + + case 7: /*ID?*/ + return 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); + } + break; + case 0xc02: /*Status - I think!*/ + voice_count = (voice_count + 1) & 0x1f; +/* emu8k->c02_read ^= 0x1000; + pclog("Read status %04X\n", 0x803f | (voice_count << 8));*/ + return 0x803f | (voice_count << 8); + } +/* fatal("Bad EMU8K inw from %08X\n", addr);*/ + return 0xffff; +} + +void emu8k_outw(uint32_t addr, uint16_t val, void *p) +{ + emu8k_t *emu8k = (emu8k_t *)p; + + emu8k_update(emu8k); +/* pclog("emu8k_outw : addr=%08X reg=%i voice=%i val=%04X\n", addr, emu8k->cur_reg, emu8k->cur_voice, val);*/ +//emu8k_outw : addr=00000A22 reg=3 voice=21 val=0265 + addr -= 0x220; + switch (addr & 0xc02) + { + case 0x400: case 0x402: /*Data0*/ + switch (emu8k->cur_reg) + { + case 0: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); + return; + + case 1: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ptrx, val); + return; + + case 2: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cvcf, val); + return; + + case 3: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].vtft, val); + return; + + case 6: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].psst, val); + emu8k->voice[emu8k->cur_voice].loop_start = (uint64_t)(emu8k->voice[emu8k->cur_voice].psst & 0xffffff) << 32; + if (addr & 2) + { + emu8k->voice[emu8k->cur_voice].vol_l = val >> 8; + emu8k->voice[emu8k->cur_voice].vol_r = 255 - (val >> 8); + } +/* pclog("emu8k_outl : write PSST %08X l %i r %i\n", emu8k->voice[emu8k->cur_voice].psst, emu8k->voice[emu8k->cur_voice].vol_l, emu8k->voice[emu8k->cur_voice].vol_r);*/ + return; + + case 7: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); + emu8k->voice[emu8k->cur_voice].loop_end = (uint64_t)(emu8k->voice[emu8k->cur_voice].cpf & 0xffffff) << 32; +/* pclog("emu8k_outl : write CPF %08X\n", emu8k->voice[emu8k->cur_voice].cpf);*/ + return; + } + break; + + case 0x800: /*Data1*/ + switch (emu8k->cur_reg) + { + case 0: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val); + emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & 0xffffff) << 32; +/* pclog("emu8k_outl : write CCCA %08X\n", emu8k->voice[emu8k->cur_voice].ccca);*/ + return; + + case 1: + switch (emu8k->cur_voice) + { + case 20: + WRITE16(addr, emu8k->smalr, val); + return; + case 21: + WRITE16(addr, emu8k->smarr, val); + return; + case 22: + WRITE16(addr, emu8k->smalw, val); + return; + case 23: + WRITE16(addr, emu8k->smarw, val); + return; + + case 26: + EMU8K_WRITE(emu8k, emu8k->smalw, val); +/* pclog("emu8k_SMLW %04X %08X\n", val, emu8k->smalw);*/ +/* if (val = 0xffff && emu8k->smalw == 0x200000) + output = 3;*/ + emu8k->smalw++; + break; + + case 29: /*Configuration Word 1*/ + emu8k->hwcf1 = val; + return; + case 30: /*Configuration Word 2*/ + emu8k->hwcf2 = val; + return; + case 31: /*Configuration Word 3*/ + emu8k->hwcf3 = val; + return; + } + break; + + case 5: +/* pclog("emu8k_outw : write DCYSUSV %04X\n", val);*/ + emu8k->voice[emu8k->cur_voice].dcysusv = val; + emu8k->voice[emu8k->cur_voice].env_sustain = (((val >> 8) & 0x7f) << 5) << 9; + if (val & 0x8000) /*Release*/ + { + emu8k->voice[emu8k->cur_voice].env_state = ENV_RELEASE; + emu8k->voice[emu8k->cur_voice].env_release = val & 0x7f; + } + else /*Decay*/ + emu8k->voice[emu8k->cur_voice].env_decay = val & 0x7f; + if (val & 0x80) + emu8k->voice[emu8k->cur_voice].env_state = ENV_STOPPED; + return; + + case 7: +/* pclog("emu8k_outw : write DCYSUS %04X\n", val);*/ + emu8k->voice[emu8k->cur_voice].dcysus = val; + emu8k->voice[emu8k->cur_voice].menv_sustain = (((val >> 8) & 0x7f) << 5) << 9; + if (val & 0x8000) /*Release*/ + { + emu8k->voice[emu8k->cur_voice].menv_state = ENV_RELEASE; + emu8k->voice[emu8k->cur_voice].menv_release = val & 0x7f; + } + else /*Decay*/ + emu8k->voice[emu8k->cur_voice].menv_decay = val & 0x7f; + if (val & 0x80) + emu8k->voice[emu8k->cur_voice].menv_state = ENV_STOPPED; + return; + } + break; + + case 0x802: /*Data2*/ + switch (emu8k->cur_reg) + { + case 0: + { + float q; + + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val); + emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & 0xffffff) << 32; + + q = (float)(emu8k->voice[emu8k->cur_voice].ccca >> 28) / 15.0f; + q /= 10.0f; /*Horrible and wrong hack*/ + emu8k->voice[emu8k->cur_voice].q = (int32_t)((1.0f / (0.707f + q)) * 256.0f); + +/* pclog("emu8k_outl : write CCCA %08X Q %f invQ %X\n", emu8k->voice[emu8k->cur_voice].ccca, q, emu8k->voice[emu8k->cur_voice].q);*/ + } + return; + + case 1: + switch (emu8k->cur_voice) + { + case 20: + WRITE16(addr, emu8k->smalr, val); + return; + case 21: + WRITE16(addr, emu8k->smarr, val); + return; + case 22: + WRITE16(addr, emu8k->smalw, val); + return; + case 23: + WRITE16(addr, emu8k->smarw, val); + return; + + case 26: + EMU8K_WRITE(emu8k, emu8k->smarw, val); +/* pclog("emu8k_SMRW %04X %08X\n", val, emu8k->smarw);*/ + emu8k->smarw++; + break; + } + break; + + case 4: +/* pclog("emu8k_outw : write ATKHLDV %04X\n", val);*/ + emu8k->voice[emu8k->cur_voice].atkhldv = val; + emu8k->voice[emu8k->cur_voice].env_attack = (val & 0x7f) << 6; + if (!(val & 0x8000)) /*Trigger attack*/ + emu8k->voice[emu8k->cur_voice].env_state = ENV_ATTACK; + return; + + case 6: +/* pclog("emu8k_outw : write ATKHLD %04X\n", val);*/ + emu8k->voice[emu8k->cur_voice].atkhld = val; + emu8k->voice[emu8k->cur_voice].menv_attack = (val & 0x7f) << 6; + if (!(val & 0x8000)) /*Trigger attack*/ + emu8k->voice[emu8k->cur_voice].menv_state = ENV_ATTACK; + return; + } + break; + + case 0xc00: /*Data3*/ + switch (emu8k->cur_reg) + { + case 0: + emu8k->voice[emu8k->cur_voice].ip = val; + emu8k->voice[emu8k->cur_voice].pitch = val; + return; + + case 1: + emu8k->voice[emu8k->cur_voice].ifatn = val; + emu8k->voice[emu8k->cur_voice].attenuation = attentable[val & 0xff]; + emu8k->voice[emu8k->cur_voice].cutoff = (val >> 8); +/* pclog("Attenuation now %02X %i\n", val & 0xff, emu8k->voice[emu8k->cur_voice].attenuation);*/ + return; + + case 2: + emu8k->voice[emu8k->cur_voice].pefe = val; + emu8k->voice[emu8k->cur_voice].fe_height = (int8_t)(val & 0xff); + return; + + case 3: + emu8k->voice[emu8k->cur_voice].fmmod = val; + emu8k->voice[emu8k->cur_voice].lfo1_fmmod = (val >> 8); + return; + + case 4: + emu8k->voice[emu8k->cur_voice].tremfrq = val; + emu8k->voice[emu8k->cur_voice].lfo1_trem = (val >> 8); + return; + + case 5: + emu8k->voice[emu8k->cur_voice].fm2frq2 = val; + emu8k->voice[emu8k->cur_voice].lfo2_fmmod = (val >> 8); + return; + + case 7: /*ID?*/ + emu8k->id = val; + return; + } + break; + + case 0xc02: /*Pointer*/ + emu8k->cur_voice = (val & 31); + emu8k->cur_reg = ((val >> 5) & 7); + return; + } +} + +uint8_t emu8k_inb(uint32_t addr, void *p) +{ + if (addr & 1) + return emu8k_inw(addr & ~1, p) >> 1; + return emu8k_inw(addr, p) & 0xff; +} + +void emu8k_outb(uint32_t addr, uint8_t val, void *p) +{ + if (addr & 1) + emu8k_outw(addr & ~1, val << 8, p); + else + emu8k_outw(addr, val, p); +} + +void emu8k_update(emu8k_t *emu8k) +{ + int new_pos = (sound_pos_global * 44100) / 48000; + if (emu8k->pos < new_pos) + { + int32_t *buf; + int pos; + int c; + int32_t out_l = 0, out_r = 0; + + buf = &emu8k->buffer[emu8k->pos*2]; + + for (pos = emu8k->pos; pos < new_pos; pos++) + emu8k->buffer[pos*2] = emu8k->buffer[pos*2 + 1] = 0; + + for (c = 0; c < 32; c++) + { + buf = &emu8k->buffer[emu8k->pos*2]; + + for (pos = emu8k->pos; pos < new_pos; pos++) + { + int32_t voice_l, voice_r; + int32_t dat; + int lfo1_vibrato, lfo2_vibrato; + int tremolo; + + tremolo = ((lfotable[(emu8k->voice[c].lfo1_count >> 8) & 4095] * emu8k->voice[c].lfo1_trem) * 4) >> 12; + + if (freqtable[emu8k->voice[c].pitch] >> 32) + dat = EMU8K_READ(emu8k, emu8k->voice[c].addr >> 32); + else + dat = EMU8K_READ_INTERP(emu8k, emu8k->voice[c].addr >> 24); + + dat = (dat * emu8k->voice[c].attenuation) >> 16; + + dat = (dat * envtable[emu8k->voice[c].env_vol >> 9]) >> 16; + + if ((emu8k->voice[c].ccca >> 28) || (emu8k->voice[c].cutoff != 0xff)) + { + int cutoff = emu8k->voice[c].cutoff + ((emu8k->voice[c].menv_vol * emu8k->voice[c].fe_height) >> 20); + if (cutoff < 0) + cutoff = 0; + if (cutoff > 255) + cutoff = 255; + + emu8k->voice[c].vhp = ((-emu8k->voice[c].vbp * emu8k->voice[c].q) >> 8) - emu8k->voice[c].vlp - dat; + emu8k->voice[c].vlp += (emu8k->voice[c].vbp * filt_w0[cutoff]) >> 8; + emu8k->voice[c].vbp += (emu8k->voice[c].vhp * filt_w0[cutoff]) >> 8; + if (emu8k->voice[c].vlp < -32767) + dat = -32767; + else if (emu8k->voice[c].vlp > 32767) + dat = 32767; + else + dat = (int16_t)emu8k->voice[c].vlp; + } + + voice_l = (dat * emu8k->voice[c].vol_l) >> 7; + voice_r = (dat * emu8k->voice[c].vol_r) >> 7; + + (*buf++) += voice_l * 8192; + (*buf++) += voice_r * 8192; + + switch (emu8k->voice[c].env_state) + { + case ENV_ATTACK: + emu8k->voice[c].env_vol += emu8k->voice[c].env_attack; + emu8k->voice[c].vtft |= 0xffff0000; + if (emu8k->voice[c].env_vol >= (1 << 21)) + { + emu8k->voice[c].env_vol = 1 << 21; + emu8k->voice[c].env_state = ENV_DECAY; + } + break; + + case ENV_DECAY: + emu8k->voice[c].env_vol -= emu8k->voice[c].env_decay; + emu8k->voice[c].vtft = (emu8k->voice[c].vtft & ~0xffff0000) | ((emu8k->voice[c].env_sustain >> 5) << 16); + if (emu8k->voice[c].env_vol <= emu8k->voice[c].env_sustain) + { + emu8k->voice[c].env_vol = emu8k->voice[c].env_sustain; + emu8k->voice[c].env_state = ENV_SUSTAIN; + } + break; + + case ENV_RELEASE: + emu8k->voice[c].env_vol -= emu8k->voice[c].env_release; + emu8k->voice[c].vtft &= ~0xffff0000; + if (emu8k->voice[c].env_vol <= 0) + { + emu8k->voice[c].env_vol = 0; + emu8k->voice[c].env_state = ENV_STOPPED; + } + break; + } + + if (emu8k->voice[c].env_vol >= (1 << 21)) + emu8k->voice[c].cvcf &= ~0xffff0000; + else + emu8k->voice[c].cvcf = (emu8k->voice[c].cvcf & ~0xffff0000) | ((emu8k->voice[c].env_vol >> 5) << 16); + + switch (emu8k->voice[c].menv_state) + { + case ENV_ATTACK: + emu8k->voice[c].menv_vol += emu8k->voice[c].menv_attack; + if (emu8k->voice[c].menv_vol >= (1 << 21)) + { + emu8k->voice[c].menv_vol = 1 << 21; + emu8k->voice[c].menv_state = ENV_DECAY; + } + break; + + case ENV_DECAY: + emu8k->voice[c].menv_vol -= emu8k->voice[c].menv_decay; + if (emu8k->voice[c].menv_vol <= emu8k->voice[c].menv_sustain) + { + emu8k->voice[c].menv_vol = emu8k->voice[c].menv_sustain; + emu8k->voice[c].menv_state = ENV_SUSTAIN; + } + break; + + case ENV_RELEASE: + emu8k->voice[c].menv_vol -= emu8k->voice[c].menv_release; + if (emu8k->voice[c].menv_vol <= 0) + { + emu8k->voice[c].menv_vol = 0; + emu8k->voice[c].menv_state = ENV_STOPPED; + } + break; + } + + lfo1_vibrato = (lfotable[(emu8k->voice[c].lfo1_count >> 8) & 4095] * emu8k->voice[c].lfo1_fmmod) >> 9; + lfo2_vibrato = (lfotable[(emu8k->voice[c].lfo2_count >> 8) & 4095] * emu8k->voice[c].lfo2_fmmod) >> 9; + + emu8k->voice[c].addr += freqtable[(emu8k->voice[c].pitch + lfo1_vibrato + lfo2_vibrato) & 0xffff]; + if (emu8k->voice[c].addr >= emu8k->voice[c].loop_end) + emu8k->voice[c].addr -= (emu8k->voice[c].loop_end - emu8k->voice[c].loop_start); + + emu8k->voice[c].lfo1_count += (emu8k->voice[c].tremfrq & 0xff); + emu8k->voice[c].lfo2_count += (emu8k->voice[c].fm2frq2 & 0xff); + } + } + + buf = &emu8k->buffer[emu8k->pos*2]; + + for (pos = emu8k->pos; pos < new_pos; pos++) + { + buf[0] >>= 15; + buf[1] >>= 15; + + if (buf[0] < -32768) + buf[0] = -32768; + else if (buf[0] > 32767) + buf[0] = 32767; + + if (buf[1] < -32768) + buf[1] = -32768; + else if (buf[1] > 32767) + buf[1] = 32767; + + buf += 2; + } + + emu8k->wc += (new_pos - emu8k->pos); + + emu8k->pos = new_pos; + } +} + +void emu8k_init(emu8k_t *emu8k, int onboard_ram) +{ + FILE *f; + int c; + double out; + + f = romfopen("roms/awe32.raw", "rb"); + if (!f) + fatal("ROMS/AWE32.RAW not found\n"); + + if (onboard_ram) + { + emu8k->ram = malloc(onboard_ram * 1024); + emu8k->ram_end_addr = 0x200000 + ((onboard_ram * 1024) / 2); + } + + emu8k->rom = malloc(1024 * 1024); + + fread(emu8k->rom, 1024 * 1024, 1, f); + fclose(f); + + /*AWE-DUMP creates ROM images offset by 2 bytes, so if we detect this + then correct it*/ + if (emu8k->rom[3] == 0x314d && emu8k->rom[4] == 0x474d) + { + memcpy(&emu8k->rom[0], &emu8k->rom[1], (1024 * 1024) - 2); + emu8k->rom[0x7ffff] = 0; + } + io_sethandler(0x0620, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(0x0a20, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(0x0e20, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + + /*Create frequency table*/ + for (c = 0; c < 0x10000; c++) + { + freqtable[c] = (uint64_t)(exp2((double)(c - 0xe000) / 4096.0) * 65536.0 * 65536.0); + } + + out = 65536.0; + + for (c = 0; c < 256; c++) + { + attentable[c] = (int)out; + out /= sqrt(1.09018); /*0.375 dB steps*/ + } + + out = 65536; + + for (c = 0; c < 4096; c++) + { + envtable[4095 - c] = (int)out; + out /= 1.002709201; /*0.0235 dB Steps*/ + } + + for (c = 0; c < 4096; c++) + { + int d = (c + 1024) & 4095; + if (d >= 2048) + lfotable[c] = 4096 - ((2048 - d) * 4); + else + lfotable[c] = (d * 4) - 4096; + } + + out = 125.0; + for (c = 0; c < 256; c++) + { +/* filt_w0[c] = (int32_t)((2.0 * 3.142 * (out / 44100.0)) * 0.707 * 256.0);*/ +/* filt_w0[c] = 2.0 * 3.142 * (out / 44100.0);*/ + filt_w0[c] = (int32_t)(2.0 * 3.142 * (out / 44100.0) * 256.0); + out *= 1.016378315; + } + + emu8k->hwcf1 = 0x59; + emu8k->hwcf2 = 0x20; + emu8k->hwcf3 = 0x04; +} + +void emu8k_close(emu8k_t *emu8k) +{ + free(emu8k->rom); + free(emu8k->ram); +} diff --git a/src/sound_emu8k.h b/src/sound_emu8k.h new file mode 100644 index 000000000..79478ad56 --- /dev/null +++ b/src/sound_emu8k.h @@ -0,0 +1,90 @@ +typedef struct emu8k_t +{ + struct + { + uint32_t cpf; + uint32_t ptrx; + uint32_t cvcf; + uint32_t vtft; + uint32_t psst; + uint32_t csl; + + uint32_t ccca; + + uint16_t init1, init2, init3, init4; + + uint16_t envvol; + uint16_t dcysusv; + uint16_t envval; + uint16_t dcysus; + uint16_t atkhldv; + uint16_t lfo1val, lfo2val; + uint16_t atkhld; + uint16_t ip; + uint16_t ifatn; + uint16_t pefe; + uint16_t fmmod; + uint16_t tremfrq; + uint16_t fm2frq2; + + int voice_on; + + uint64_t addr; + uint64_t loop_start, loop_end; + + uint16_t pitch; + int attenuation; + int env_state, env_vol; + int env_attack, env_decay, env_sustain, env_release; + + int menv_state, menv_vol; + int menv_attack, menv_decay, menv_sustain, menv_release; + + int lfo1_count, lfo2_count; + int8_t lfo1_fmmod, lfo2_fmmod; + int8_t lfo1_trem; + int vol_l, vol_r; + + int8_t fe_height; + + int64_t vlp, vbp, vhp; + int32_t q; + + int filter_offset; + +/* float vlp, vbp, vhp; + float q;*/ + + int cutoff; + } voice[32]; + + uint32_t hwcf1, hwcf2, hwcf3; + uint32_t hwcf4, hwcf5, hwcf6; + + uint32_t smalr, smarr, smalw, smarw; + uint16_t smld_buffer, smrd_buffer; + + uint16_t wc; + + uint16_t c02_read; + + uint16_t id; + + int16_t *ram, *rom; + + uint32_t ram_end_addr; + + int cur_reg, cur_voice; + + int timer_count; + + int16_t out_l, out_r; + + int pos; + int32_t buffer[SOUNDBUFLEN * 2]; +} emu8k_t; + +void emu8k_init(emu8k_t *emu8k, int onboard_ram); +void emu8k_close(emu8k_t *emu8k); + +void emu8k_update(emu8k_t *emu8k); diff --git a/src/sound_gus.c b/src/sound_gus.c new file mode 100644 index 000000000..6ff19a254 --- /dev/null +++ b/src/sound_gus.c @@ -0,0 +1,1138 @@ +#include +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "sound.h" +#include "sound_gus.h" +#include "timer.h" + +typedef struct gus_t +{ + int reset; + + int global; + uint32_t addr,dmaaddr; + int voice; + uint32_t start[32],end[32],cur[32]; + uint32_t startx[32],endx[32],curx[32]; + int rstart[32],rend[32]; + int rcur[32]; + uint16_t freq[32]; + uint16_t rfreq[32]; + uint8_t ctrl[32]; + uint8_t rctrl[32]; + int curvol[32]; + int pan_l[32], pan_r[32]; + int t1on,t2on; + uint8_t tctrl; + uint16_t t1,t2,t1l,t2l; + uint8_t irqstatus,irqstatus2; + uint8_t adcommand; + int waveirqs[32],rampirqs[32]; + int voices; + uint8_t dmactrl; + + int32_t out_l, out_r; + + int16_t buffer[2][SOUNDBUFLEN]; + int pos; + + int samp_timer, samp_latch; + + uint8_t *ram; + + int irqnext; + + int timer_1, timer_2; + + int irq, dma, irq_midi; + int latch_enable; + + uint8_t sb_2xa, sb_2xc, sb_2xe; + uint8_t sb_ctrl; + int sb_nmi; + + uint8_t reg_ctrl; + + uint8_t ad_status, ad_data; + uint8_t ad_timer_ctrl; + + uint8_t midi_ctrl, midi_status; + uint8_t midi_data; + int midi_loopback; + + uint8_t gp1, gp2; + uint16_t gp1_addr, gp2_addr; + + uint8_t usrr; +} gus_t; + +static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; + +int gusfreqs[]= +{ + 44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696, + 23746,22866,22050,21289,20580,19916,19293 +}; + +double vol16bit[4096]; + +void pollgusirqs(gus_t *gus) +{ + int c; + + gus->irqstatus&=~0x60; + for (c=0;c<32;c++) + { + if (gus->waveirqs[c]) + { +// gus->waveirqs[c]=0; + gus->irqstatus2=0x60|c; + if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; + gus->irqstatus|=0x20; +// printf("Voice IRQ %i %02X %i\n",c,gus->irqstatus2,ins); + if (gus->irq != -1) + picint(1 << gus->irq); + return; + } + if (gus->rampirqs[c]) + { +// gus->rampirqs[c]=0; + gus->irqstatus2=0xA0|c; + gus->irqstatus|=0x40; +// printf("Ramp IRQ %i %02X %i\n",c,gus->irqstatus2,ins); + if (gus->irq != -1) + picint(1 << gus->irq); + return; + } + } + gus->irqstatus2=0xE0; +// gus->irqstatus&=~0x20; + if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); +} + +enum +{ + MIDI_INT_RECEIVE = 0x01, + MIDI_INT_TRANSMIT = 0x02, + MIDI_INT_MASTER = 0x80 +}; + +enum +{ + MIDI_CTRL_TRANSMIT_MASK = 0x60, + MIDI_CTRL_TRANSMIT = 0x20, + MIDI_CTRL_RECEIVE = 0x80 +}; + +enum +{ + GUS_INT_MIDI_TRANSMIT = 0x01, + GUS_INT_MIDI_RECEIVE = 0x02 +}; + +enum +{ + GUS_TIMER_CTRL_AUTO = 0x01 +}; + +void gus_midi_update_int_status(gus_t *gus) +{ + gus->midi_status &= ~MIDI_INT_MASTER; + if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_TRANSMIT; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; + + if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_RECEIVE; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; + + if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) + { +// pclog("Take MIDI IRQ\n"); + picint(1 << gus->irq_midi); + } +} + +void writegus(uint16_t addr, uint8_t val, void *p) +{ + gus_t *gus = (gus_t *)p; + int c, d; + int old; +// pclog("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc); + if (gus->latch_enable && addr != 0x24b) + gus->latch_enable = 0; + switch (addr) + { + case 0x340: /*MIDI control*/ + old = gus->midi_ctrl; + gus->midi_ctrl = val; + + if ((val & 3) == 3) + gus->midi_status = 0; + else if ((old & 3) == 3) + { + gus->midi_status |= MIDI_INT_TRANSMIT; +// pclog("MIDI_INT_TRANSMIT\n"); + } + gus_midi_update_int_status(gus); + break; + + case 0x341: /*MIDI data*/ + if (gus->midi_loopback) + { + gus->midi_status |= MIDI_INT_RECEIVE; + gus->midi_data = val; + } + else + gus->midi_status |= MIDI_INT_TRANSMIT; + break; + + case 0x342: /*Voice select*/ + gus->voice=val&31; + break; + case 0x343: /*Global select*/ + gus->global=val; + break; + case 0x344: /*Global low*/ +// if (gus->global!=0x43 && gus->global!=0x44) printf("Writing register %02X %02X %02X %i\n",gus->global,gus->voice,val, ins); + switch (gus->global) + { + case 0: /*Voice control*/ +// if (val&1 && !(gus->ctrl[gus->voice]&1)) printf("Voice on %i\n",gus->voice); + gus->ctrl[gus->voice]=val; + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF00)|val; + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0xF807F)|(val<<7); + gus->start[gus->voice]=(gus->start[gus->voice]&0x1F00FFFF)|(val<<16); +// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); + break; + case 3: /*Start addr low*/ + gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFFFF00)|val; +// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); + break; + case 4: /*End addr high*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0xF807F)|(val<<7); + gus->end[gus->voice]=(gus->end[gus->voice]&0x1F00FFFF)|(val<<16); +// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); + break; + case 5: /*End addr low*/ + gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val; +// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); + break; + + case 0x6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); +// printf("RFREQ %02X %i %i %f\n",val,gus->voice,gus->rfreq[gus->voice],(double)(val & 63)/(double)(1 << (3*(val >> 6)))); + break; + + case 0x9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); +// printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]); + break; + + case 0xA: /*Current addr high*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1F00FFFF)|(val<<16); +gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); +// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0F807F00)|((val<<7)<<8); +// printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFFFF00)|val; +// printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); + break; + + case 0x42: /*DMA address low*/ + gus->dmaaddr=(gus->dmaaddr&0xFF000)|(val<<4); + break; + + case 0x43: /*Address low*/ + gus->addr=(gus->addr&0xFFF00)|val; + break; + case 0x45: /*Timer control*/ +// printf("Timer control %02X\n",val); + gus->tctrl=val; + break; + } + break; + case 0x345: /*Global high*/ +// if (gus->global!=0x43 && gus->global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X %i %X\n",gus->global,gus->voice,val,CS,pc, ins, gus->rcur[1] >> 10); + switch (gus->global) + { + case 0: /*Voice control*/ + if (!(val&1) && gus->ctrl[gus->voice]&1) + { +// printf("Voice on %i - start %05X end %05X freq %04X\n",gus->voice,gus->start[gus->voice],gus->end[gus->voice],gus->freq[gus->voice]); +// if (val&0x40) gus->cur[gus->voice]=gus->end[gus->voice]<<8; +// else gus->cur[gus->voice]=gus->start[gus->voice]<<8; + } + + gus->ctrl[gus->voice] = val & 0x7f; + + old = gus->waveirqs[gus->voice]; + gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->waveirqs[gus->voice] != old) + pollgusirqs(gus); + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF)|(val<<8); + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0x07FFF)|(val<<15); + gus->start[gus->voice]=(gus->start[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); +// printf("Write %i start %08X %08X %02X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice],val); + break; + case 3: /*Start addr low*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0xFFF80)|(val&0x7F); + gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFF00FF)|(val<<8); +// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); + break; + case 4: /*End addr high*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0x07FFF)|(val<<15); + gus->end[gus->voice]=(gus->end[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); +// printf("Write %i end %08X %08X %02X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice],val); + break; + case 5: /*End addr low*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0xFFF80)|(val&0x7F); + gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8); +// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); + break; + + case 0x6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); +// pclog("Ramp freq %02X %i %i %f %i\n", val, gus->voice, gus->rfreq[gus->voice], (double)(val & 63)/(double)(1 << (3*(val >> 6))), ins); + break; + case 0x7: /*Ramp start*/ + gus->rstart[gus->voice] = val << 14; +// pclog("Ramp start %04X\n", gus->rstart[gus->voice] >> 10); + break; + case 0x8: /*Ramp end*/ + gus->rend[gus->voice] = val << 14; +// pclog("Ramp end %04X\n", gus->rend[gus->voice] >> 10); + break; + case 0x9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); +// printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]); + break; + + case 0xA: /*Current addr high*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); + gus->curx[gus->voice]=(gus->curx[gus->voice]&0x07FFF00)|((val<<15)<<8); +// printf("Write %i cur %08X %08X %02X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice],val); +// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x007FFF00)|((val<<15)<<8); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFF00FF)|(val<<8); +gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); +// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0FFF8000)|((val&0x7F)<<8); +// printf("Write %i cur %08X %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); + break; + case 0xC: /*Pan*/ + gus->pan_l[gus->voice] = 15 - (val & 0xf); + gus->pan_r[gus->voice] = (val & 0xf); + break; + case 0xD: /*Ramp control*/ + old = gus->rampirqs[gus->voice]; + gus->rctrl[gus->voice] = val & 0x7F; + gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->rampirqs[gus->voice] != old) + pollgusirqs(gus); +// printf("Ramp control %02i %02X %02X %i\n",gus->voice,val,gus->rampirqs[gus->voice],ins); + break; + + case 0xE: + gus->voices=(val&63)+1; + if (gus->voices>32) gus->voices=32; + if (gus->voices<14) gus->voices=14; + gus->global=val; +// printf("GUS voices %i\n",val&31); + if (gus->voices < 14) + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + break; + + case 0x41: /*DMA*/ + if (val&1 && gus->dma != -1) + { +// printf("DMA start! %05X %02X\n",gus->dmaaddr,val); + if (val & 2) + { + c=0; + while (c<65536) + { + int dma_result; + d = gus->ram[gus->dmaaddr]; + if (val & 0x80) d ^= 0x80; + dma_result = dma_channel_write(gus->dma, d); + if (dma_result == DMA_NODATA) + break; + gus->dmaaddr++; + gus->dmaaddr&=0xFFFFF; + c++; + if (dma_result & DMA_OVER) + break; + } +// printf("GUS->MEM Transferred %i bytes\n",c); + gus->dmactrl=val&~0x40; + if (val&0x20) gus->irqnext=1; + } + else + { + c=0; + while (c<65536) + { + d = dma_channel_read(gus->dma); + if (d == DMA_NODATA) + break; + if (val&0x80) d^=0x80; + gus->ram[gus->dmaaddr]=d; + gus->dmaaddr++; + gus->dmaaddr&=0xFFFFF; + c++; + if (d & DMA_OVER) + break; + } +// printf("MEM->GUS Transferred %i bytes\n",c); + gus->dmactrl=val&~0x40; + if (val&0x20) gus->irqnext=1; + } +// exit(-1); + } + break; + + case 0x42: /*DMA address low*/ + gus->dmaaddr=(gus->dmaaddr&0xFF0)|(val<<12); + break; + + case 0x43: /*Address low*/ + gus->addr=(gus->addr&0xF00FF)|(val<<8); + break; + case 0x44: /*Address high*/ + gus->addr=(gus->addr&0xFFFF)|((val<<16)&0xF0000); + break; + case 0x45: /*Timer control*/ + if (!(val&4)) gus->irqstatus&=~4; + if (!(val&8)) gus->irqstatus&=~8; + if (!(val & 0x20)) + { + gus->ad_status &= ~0x18; + nmi = 0; + } + if (!(val & 0x02)) + { + gus->ad_status &= ~0x01; + nmi = 0; + } +// printf("Timer control %02X\n",val); +/* if ((val&4) && !(gus->tctrl&4)) + { + gus->t1=gus->t1l; + gus->t1on=1; + }*/ + gus->tctrl=val; + gus->sb_ctrl = val; + break; + case 0x46: /*Timer 1*/ + gus->t1 = gus->t1l = val; + gus->t1on = 1; +// printf("GUS timer 1 %i\n",val); + break; + case 0x47: /*Timer 2*/ + gus->t2 = gus->t2l = val; + gus->t2on = 1; +// printf("GUS timer 2 %i\n",val); + break; + + case 0x4c: /*Reset*/ + gus->reset = val; + break; + } + break; + case 0x347: /*DRAM access*/ + gus->ram[gus->addr]=val; +// pclog("GUS RAM write %05X %02X\n",gus->addr,val); + gus->addr&=0xFFFFF; + break; + case 0x248: case 0x388: + gus->adcommand = val; +// pclog("Setting ad command %02X %02X %p\n", val, gus->adcommand, &gus->adcommand); + break; + + case 0x389: + if ((gus->tctrl & GUS_TIMER_CTRL_AUTO) || gus->adcommand != 4) + { + gus->ad_data = val; + gus->ad_status |= 0x01; + if (gus->sb_ctrl & 0x02) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + } + else if (!(gus->tctrl & GUS_TIMER_CTRL_AUTO) && gus->adcommand == 4) + { + if (val & 0x80) + { + gus->ad_status &= ~0x60; + } + else + { + gus->ad_timer_ctrl = val; + + if (val & 0x01) + gus->t1on = 1; + else + gus->t1 = gus->t1l; + + if (val & 0x02) + gus->t2on = 1; + else + gus->t2 = gus->t2l; + } + } + break; + + case 0x240: + gus->midi_loopback = val & 0x20; + gus->latch_enable = (val & 0x40) ? 2 : 1; + break; + + case 0x24b: + switch (gus->reg_ctrl & 0x07) + { + case 0: + if (gus->latch_enable == 1) + gus->dma = gus_dmas[val & 7]; + if (gus->latch_enable == 2) + { + gus->irq = gus_irqs[val & 7]; + if (val & 0x40) + gus->irq_midi = gus->irq; + else + gus->irq_midi = gus_irqs_midi[(val >> 3) & 7]; + + gus->sb_nmi = val & 0x80; + } + gus->latch_enable = 0; +// pclog("IRQ %i DMA %i\n", gus->irq, gus->dma); + break; + case 1: + gus->gp1 = val; + break; + case 2: + gus->gp2 = val; + break; + case 3: + gus->gp1_addr = val; + break; + case 4: + gus->gp2_addr = val; + break; + case 5: + gus->usrr = 0; + break; + case 6: + break; + } + break; + + case 0x246: + gus->ad_status |= 0x08; + if (gus->sb_ctrl & 0x20) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + break; + case 0x24a: + gus->sb_2xa = val; + break; + case 0x24c: + gus->ad_status |= 0x10; + if (gus->sb_ctrl & 0x20) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + case 0x24d: + gus->sb_2xc = val; + break; + case 0x24e: + gus->sb_2xe = val; + break; + case 0x24f: + gus->reg_ctrl = val; + break; + } +} + +uint8_t readgus(uint16_t addr, void *p) +{ + gus_t *gus = (gus_t *)p; + uint8_t val; +// /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus->global); + switch (addr) + { + case 0x340: /*MIDI status*/ + val = gus->midi_status; +// pclog("Read MIDI status %02X\n", val); + break; + + case 0x341: /*MIDI data*/ + val = gus->midi_data; + gus->midi_status &= ~MIDI_INT_RECEIVE; + gus_midi_update_int_status(gus); + break; + + case 0x240: return 0; + case 0x246: /*IRQ status*/ + val = gus->irqstatus & ~0x10; + if (gus->ad_status & 0x19) + val |= 0x10; +// pclog("Read IRQ status %02X\n", val); + return val; + + case 0x24F: return 0; + case 0x342: return gus->voice; + case 0x343: return gus->global; + case 0x344: /*Global low*/ +// /*if (gus->global!=0x43 && gus->global!=0x44) */printf("Reading register %02X %02X\n",gus->global,gus->voice); + switch (gus->global) + { + case 0x82: /*Start addr high*/ + return gus->start[gus->voice]>>16; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice]&0xFF; + + case 0x89: /*Current volume*/ + return gus->rcur[gus->voice]>>6; + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice]>>16; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice]&0xFF; + + case 0x8F: /*IRQ status*/ + val=gus->irqstatus2; +// pclog("Read IRQ status - %02X\n",val); + gus->rampirqs[gus->irqstatus2&0x1F]=0; + gus->waveirqs[gus->irqstatus2&0x1F]=0; + pollgusirqs(gus); + return val; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + +// default: +// fatal("Bad GUS global low read %02X\n",gus->global); + } + break; + case 0x345: /*Global high*/ +// /*if (gus->global!=0x43 && gus->global!=0x44) */printf("HReading register %02X %02X\n",gus->global,gus->voice); + switch (gus->global) + { + case 0x80: /*Voice control*/ +// pclog("Read voice control %02i %02X\n", gus->voice, gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0)); + return gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0); + + case 0x82: /*Start addr high*/ + return gus->start[gus->voice]>>24; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice]>>8; + + case 0x89: /*Current volume*/ +// pclog("Read current volume %i\n", gus->rcur[gus->voice] >> 14); + return gus->rcur[gus->voice]>>14; + + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice]>>24; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice]>>8; + + case 0x8C: /*Pan*/ + return gus->pan_r[gus->voice]; + + case 0x8D: +// pclog("Read ramp control %02X %04X %08X %08X %08X\n",gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0),gus->rcur[gus->voice] >> 14,gus->rfreq[gus->voice],gus->rstart[gus->voice],gus->rend[gus->voice]); + return gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0); + + case 0x8F: /*IRQ status*/ +// pclog("Read IRQ 1\n"); + val=gus->irqstatus2; + gus->rampirqs[gus->irqstatus2&0x1F]=0; + gus->waveirqs[gus->irqstatus2&0x1F]=0; + pollgusirqs(gus); +// pclog("Read IRQ status - %02X %i %i\n",val, gus->waveirqs[gus->irqstatus2&0x1F], gus->rampirqs[gus->irqstatus2&0x1F]); + return val; + + case 0x41: /*DMA control*/ + val=gus->dmactrl|((gus->irqstatus&0x80)?0x40:0); + gus->irqstatus&=~0x80; + return val; + case 0x45: /*Timer control*/ + return gus->tctrl; + case 0x49: /*Sampling control*/ + return 0; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + +// default: +// fatal("Bad GUS global high read %02X\n",gus->global); + } + break; + case 0x346: return 0xff; + case 0x347: /*DRAM access*/ + val=gus->ram[gus->addr]; +// pclog("GUS RAM read %05X %02X\n",gus->addr,val); + gus->addr&=0xFFFFF; + return val; + case 0x349: return 0; + case 0x746: /*Revision level*/ + return 0xff; /*Pre 3.7 - no mixer*/ + + case 0x24b: + switch (gus->reg_ctrl & 0x07) + { + case 1: + val = gus->gp1; + break; + case 2: + val = gus->gp2; + break; + case 3: + val = gus->gp1_addr; + break; + case 4: + val = gus->gp2_addr; + break; + } + break; + + case 0x24c: + val = gus->sb_2xc; + if (gus->reg_ctrl & 0x20) + gus->sb_2xc &= 0x80; + break; + case 0x24e: +/* gus->ad_status |= 0x10; + if (gus->reg_ctrl & 0x80) + { + gus->reg_ctrl_r |= 0x80; + if (gus->sb_nmi) + nmi = 1; + else + picint(1 << gus->irq); + }*/ + return gus->sb_2xe; + + case 0x248: case 0x388: +// pclog("Read ad_status %02X\n", gus->ad_status); + if (gus->tctrl & GUS_TIMER_CTRL_AUTO) + val = gus->sb_2xa; + else + { + val = gus->ad_status & ~(gus->ad_timer_ctrl & 0x60); + if (val & 0x60) + val |= 0x80; + } + break; + + case 0x249: + gus->ad_status &= ~0x01; + nmi = 0; + case 0x389: + val = gus->ad_data; + break; + + case 0x24A: + val = gus->adcommand; +// pclog("Read ad command %02X %02X %p\n", gus->adcommand, val, &gus->adcommand); + break; + + } +// printf("Bad GUS read %04X! %02X\n",addr,gus->global); +// exit(-1); + return val; +} + +void gus_poll_timer_1(void *p) +{ + gus_t *gus = (gus_t *)p; + + gus->timer_1 += (TIMER_USEC * 80); +// pclog("gus_poll_timer_1 %i %i %i %i %02X\n", gustime, gus->t1on, gus->t1, gus->t1l, gus->tctrl); + if (gus->t1on) + { + gus->t1++; + if (gus->t1 > 0xFF) + { +// gus->t1on=0; + gus->t1=gus->t1l; + gus->ad_status |= 0x40; + if (gus->tctrl&4) + { + if (gus->irq != -1) + picint(1 << gus->irq); + gus->ad_status |= 0x04; + gus->irqstatus |= 0x04; +// pclog("GUS T1 IRQ!\n"); + } + } + } + if (gus->irqnext) + { +// pclog("Take IRQ\n"); + gus->irqnext=0; + gus->irqstatus|=0x80; + if (gus->irq != -1) + picint(1 << gus->irq); + } + gus_midi_update_int_status(gus); +} + +void gus_poll_timer_2(void *p) +{ + gus_t *gus = (gus_t *)p; + + gus->timer_2 += (TIMER_USEC * 320); +// pclog("pollgus2 %i %i %i %i %02X\n", gustime, gus->t2on, gus->t2, gus->t2l, gus->tctrl); + if (gus->t2on) + { + gus->t2++; + if (gus->t2 > 0xFF) + { +// gus->t2on=0; + gus->t2=gus->t2l; + gus->ad_status |= 0x20; + if (gus->tctrl&8) + { + if (gus->irq != -1) + picint(1 << gus->irq); + gus->ad_status |= 0x02; + gus->irqstatus |= 0x08; +// pclog("GUS T2 IRQ!\n"); + } + } + } + if (gus->irqnext) + { +// pclog("Take IRQ\n"); + gus->irqnext=0; + gus->irqstatus|=0x80; + if (gus->irq != -1) + picint(1 << gus->irq); + } +} + +static void gus_update(gus_t *gus) +{ + for (; gus->pos < sound_pos_global; gus->pos++) + { + if (gus->out_l < -32768) + gus->buffer[0][gus->pos] = -32768; + else if (gus->out_l > 32767) + gus->buffer[0][gus->pos] = 32767; + else + gus->buffer[0][gus->pos] = gus->out_l; + if (gus->out_r < -32768) + gus->buffer[1][gus->pos] = -32768; + else if (gus->out_r > 32767) + gus->buffer[1][gus->pos] = 32767; + else + gus->buffer[1][gus->pos] = gus->out_r; + } +} + +void gus_poll_wave(void *p) +{ + gus_t *gus = (gus_t *)p; + uint32_t addr; + int d; + int16_t v; + int32_t vl; + int update_irqs = 0; + + gus_update(gus); + + gus->samp_timer += gus->samp_latch; + + gus->out_l = gus->out_r = 0; + + if ((gus->reset & 3) != 3) + return; +//pclog("gus_poll_wave\n"); + for (d=0;d<32;d++) + { + if (!(gus->ctrl[d] & 3)) + { + if (gus->ctrl[d] & 4) + { + addr = gus->cur[d] >> 9; + addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE); + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (gus->cur[d] & 511)); + vl += (int16_t)(int8_t)((gus->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (gus->cur[d] & 511); + v = vl >> 9; + } + else + v = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80); + } + else + { + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = ((int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (gus->cur[d] & 511)); + vl += ((int8_t)((gus->ram[((gus->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (gus->cur[d] & 511); + v = vl >> 9; + } + else + v = (int16_t)(int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80); + } + +// pclog("Voice %i : %04X %05X %04X ", d, v, gus->cur[d] >> 9, gus->rcur[d] >> 10); + if ((gus->rcur[d] >> 14) > 4095) v = (int16_t)(float)(v) * 24.0 * vol16bit[4095]; + else v = (int16_t)(float)(v) * 24.0 * vol16bit[(gus->rcur[d]>>10) & 4095]; +// pclog("%f %04X\n", vol16bit[(gus->rcur[d]>>10) & 4095], v); + + gus->out_l += (v * gus->pan_l[d]) / 7; + gus->out_r += (v * gus->pan_r[d]) / 7; + + if (gus->ctrl[d]&0x40) + { + gus->cur[d] -= (gus->freq[d] >> 1); + if (gus->cur[d] <= gus->start[d]) + { + int diff = gus->start[d] - gus->cur[d]; + if (!(gus->rctrl[d]&4)) + { + if (!(gus->ctrl[d]&8)) + { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + else + { + if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } + } + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) + { + gus->waveirqs[d] = 1; + update_irqs = 1; +// pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d); + } + } + } + else + { + gus->cur[d] += (gus->freq[d] >> 1); + + if (gus->cur[d] >= gus->end[d]) + { + int diff = gus->cur[d] - gus->end[d]; + if (!(gus->rctrl[d]&4)) + { + if (!(gus->ctrl[d]&8)) + { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + else + { + if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } + } + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) + { + gus->waveirqs[d] = 1; + update_irqs = 1; +// pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d); + } + } + } + } + if (!(gus->rctrl[d] & 3)) + { + if (gus->rctrl[d] & 0x40) + { + gus->rcur[d] -= gus->rfreq[d]; + if (gus->rcur[d] <= gus->rstart[d]) + { + int diff = gus->rstart[d] - gus->rcur[d]; + if (!(gus->rctrl[d] & 8)) + { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } + else + { + if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) + { + gus->rampirqs[d] = 1; + update_irqs = 1; +// pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d); + } + } + } + else + { + gus->rcur[d] += gus->rfreq[d]; +// if (d == 1) printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus->rfreq[d],gus->rcur[d],gus->rstart[d],gus->rend[d]); + if (gus->rcur[d] >= gus->rend[d]) + { + int diff = gus->rcur[d] - gus->rend[d]; + if (!(gus->rctrl[d] & 8)) + { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } + else + { + if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) + { + gus->rampirqs[d] = 1; + update_irqs = 1; +// pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d); + } + } + } + } + } + + if (update_irqs) + pollgusirqs(gus); +} + +static void gus_get_buffer(int32_t *buffer, int len, void *p) +{ + gus_t *gus = (gus_t *)p; + int c; + + gus_update(gus); + + for (c = 0; c < len * 2; c++) + { + buffer[c] += (int32_t)gus->buffer[c & 1][c >> 1]; + } + + gus->pos = 0; +} + + +void *gus_init() +{ + int c; + double out = 1.0; + gus_t *gus = malloc(sizeof(gus_t)); + memset(gus, 0, sizeof(gus_t)); + + gus->ram = malloc(1 << 20); + memset(gus->ram, 0, 1 << 20); + + pclog("gus_init\n"); + + for (c=0;c<32;c++) + { + gus->ctrl[c]=1; + gus->rctrl[c]=1; + gus->rfreq[c]=63*512; + } + + for (c=4095;c>=0;c--) { + vol16bit[c]=out;//(float)c/4095.0;//out; + out/=1.002709201; /* 0.0235 dB Steps */ + } + + printf("Top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]); + gus->voices=14; + + gus->samp_timer = gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + + gus->t1l = gus->t2l = 0xff; + + io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); + timer_add(gus_poll_wave, &gus->samp_timer, TIMER_ALWAYS_ENABLED, gus); + timer_add(gus_poll_timer_1, &gus->timer_1, TIMER_ALWAYS_ENABLED, gus); + timer_add(gus_poll_timer_2, &gus->timer_2, TIMER_ALWAYS_ENABLED, gus); + + sound_add_handler(gus_get_buffer, gus); + + return gus; +} + +void gus_close(void *p) +{ + gus_t *gus = (gus_t *)p; + + free(gus->ram); + free(gus); +} + +void gus_speed_changed(void *p) +{ + gus_t *gus = (gus_t *)p; + + if (gus->voices < 14) + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); +} + +device_t gus_device = +{ + "Gravis UltraSound", + 0, + gus_init, + gus_close, + NULL, + gus_speed_changed, + NULL, + NULL +}; diff --git a/src/sound_gus.h b/src/sound_gus.h new file mode 100644 index 000000000..6c124f9f8 --- /dev/null +++ b/src/sound_gus.h @@ -0,0 +1 @@ +extern device_t gus_device; diff --git a/src/sound_mameopl.c b/src/sound_mameopl.c new file mode 100644 index 000000000..caf3691b8 --- /dev/null +++ b/src/sound_mameopl.c @@ -0,0 +1,200 @@ +#include +#include +#include "ibm.h" +#include "io.h" +#include "sound.h" +#include "mame/fmopl.h" +#include "mame/ymf262.h" +#include "sound_opl.h" +#include "sound_dbopl.h" + +/*Interfaces between PCem and the actual OPL emulator*/ + + +uint8_t opl2_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return ym3812_read(opl->YM3812[0], a); +} +void opl2_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + ym3812_write(opl->YM3812[0],a,v); + ym3812_write(opl->YM3812[1],a,v); +} + +uint8_t opl2_l_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return ym3812_read(opl->YM3812[0], a); +} +void opl2_l_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + ym3812_write(opl->YM3812[0],a,v); +} + +uint8_t opl2_r_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return ym3812_read(opl->YM3812[1], a); +} +void opl2_r_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + ym3812_write(opl->YM3812[1],a,v); +} + +uint8_t opl3_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl3_update2(opl); + return ymf262_read(opl->YMF262, a); +} +void opl3_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl3_update2(opl); + ymf262_write(opl->YMF262, a, v); +} + + +void opl2_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + ym3812_update_one(opl->YM3812[0], &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + ym3812_update_one(opl->YM3812[1], &opl->buffer[opl->pos*2 + 1], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + } + } +} + +void opl3_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + ymf262_update_one(opl->YMF262, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + } + } +} + +void ym3812_timer_set_0(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} +void ym3812_timer_set_1(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[1][timer] = period * TIMER_USEC * 20; + if (!opl->timers[1][timer]) opl->timers[1][timer] = 1; + opl->timers_enable[1][timer] = period ? 1 : 0; +} + +void ymf262_timer_set(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} + +static void opl_timer_callback00(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][0] = 0; + ym3812_timer_over(opl->YM3812[0], 0); +} +static void opl_timer_callback01(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][1] = 0; + ym3812_timer_over(opl->YM3812[0], 1); +} +static void opl_timer_callback10(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][0] = 0; + ym3812_timer_over(opl->YM3812[1], 0); +} +static void opl_timer_callback11(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][1] = 0; + ym3812_timer_over(opl->YM3812[1], 1); +} +static void opl3_timer_callback00(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][0] = 0; + ymf262_timer_over(opl->YMF262, 0); +} +static void opl3_timer_callback01(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][1] = 0; + ymf262_timer_over(opl->YMF262, 1); +} + +void opl2_init(opl_t *opl) +{ + opl->YM3812[0] = ym3812_init(NULL, 3579545, 48000); + ym3812_reset_chip(opl->YM3812[0]); + ym3812_set_timer_handler(opl->YM3812[0], ym3812_timer_set_0, opl); + + opl->YM3812[1] = ym3812_init(NULL, 3579545, 48000); + ym3812_reset_chip(opl->YM3812[1]); + ym3812_set_timer_handler(opl->YM3812[1], ym3812_timer_set_1, opl); + + timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); + timer_add(opl_timer_callback10, &opl->timers[1][0], &opl->timers_enable[1][0], (void *)opl); + timer_add(opl_timer_callback11, &opl->timers[1][1], &opl->timers_enable[1][1], (void *)opl); +} + +void opl3_init(opl_t *opl) +{ + opl->YMF262 = ymf262_init(NULL, 3579545 * 4, 48000); + ymf262_reset_chip(opl->YMF262); + ymf262_set_timer_handler(opl->YMF262, ymf262_timer_set, opl); + timer_add(opl3_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl3_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); +} + diff --git a/src/sound_mpu401_uart.c b/src/sound_mpu401_uart.c new file mode 100644 index 000000000..3ff22de61 --- /dev/null +++ b/src/sound_mpu401_uart.c @@ -0,0 +1,57 @@ +#include "ibm.h" +#include "io.h" +#include "sound_mpu401_uart.h" + +enum +{ + STATUS_OUTPUT_NOT_READY = 0x40, + STATUS_INPUT_NOT_READY = 0x80 +}; + +static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) +{ + mpu401_uart_t *mpu = (mpu401_uart_t *)p; + + if (addr & 1) /*Command*/ + { + switch (val) + { + case 0xff: /*Reset*/ + mpu->rx_data = 0xfe; /*Acknowledge*/ + mpu->status = 0; + mpu->uart_mode = 0; + break; + + case 0x3f: /*Enter UART mode*/ + mpu->rx_data = 0xfe; /*Acknowledge*/ + mpu->status = 0; + mpu->uart_mode = 1; + break; + } + return; + } + + /*Data*/ + if (mpu->uart_mode) + midi_write(val); +} + +static uint8_t mpu401_uart_read(uint16_t addr, void *p) +{ + mpu401_uart_t *mpu = (mpu401_uart_t *)p; + + if (addr & 1) /*Status*/ + return mpu->status; + + /*Data*/ + mpu->status |= STATUS_INPUT_NOT_READY; + return mpu->rx_data; +} + +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr) +{ + mpu->status = STATUS_INPUT_NOT_READY; + mpu->uart_mode = 0; + + io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); +} diff --git a/src/sound_mpu401_uart.h b/src/sound_mpu401_uart.h new file mode 100644 index 000000000..893c53fc4 --- /dev/null +++ b/src/sound_mpu401_uart.h @@ -0,0 +1,9 @@ +typedef struct mpu401_uart_t +{ + uint8_t status; + uint8_t rx_data; + + int uart_mode; +} mpu401_uart_t; + +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr); diff --git a/src/sound_opl.c b/src/sound_opl.c new file mode 100644 index 000000000..e555f46be --- /dev/null +++ b/src/sound_opl.c @@ -0,0 +1,176 @@ +#include +#include +#include "ibm.h" +#include "io.h" +#include "sound.h" +#include "sound_opl.h" +#include "sound_dbopl.h" + +/*Interfaces between PCem and the actual OPL emulator*/ + + +uint8_t opl2_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return opl_read(0, a); +} +void opl2_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(0, a, v); + opl_write(1, a, v); +} + +uint8_t opl2_l_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return opl_read(0, a); +} +void opl2_l_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(0, a, v); +} + +uint8_t opl2_r_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return opl_read(1, a); +} +void opl2_r_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(1, a, v); +} + +uint8_t opl3_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl3_update2(opl); + return opl_read(0, a); +} +void opl3_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl3_update2(opl); + opl_write(0, a, v); +} + + +void opl2_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + opl2_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + opl2_update(1, &opl->buffer[opl->pos*2 + 1], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + } + } +} + +void opl3_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + opl3_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + } + } +} + +void ym3812_timer_set_0(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} +void ym3812_timer_set_1(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[1][timer] = period * TIMER_USEC * 20; + if (!opl->timers[1][timer]) opl->timers[1][timer] = 1; + opl->timers_enable[1][timer] = period ? 1 : 0; +} + +void ymf262_timer_set(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} + +static void opl_timer_callback00(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][0] = 0; + opl_timer_over(0, 0); +} +static void opl_timer_callback01(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][1] = 0; + opl_timer_over(0, 1); +} +static void opl_timer_callback10(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][0] = 0; + opl_timer_over(1, 0); +} +static void opl_timer_callback11(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][1] = 0; + opl_timer_over(1, 1); +} + +void opl2_init(opl_t *opl) +{ + opl_init(ym3812_timer_set_0, opl, 0, 0); + opl_init(ym3812_timer_set_1, opl, 1, 0); + timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); + timer_add(opl_timer_callback10, &opl->timers[1][0], &opl->timers_enable[1][0], (void *)opl); + timer_add(opl_timer_callback11, &opl->timers[1][1], &opl->timers_enable[1][1], (void *)opl); +} + +void opl3_init(opl_t *opl) +{ + opl_init(ymf262_timer_set, opl, 0, 1); + timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); +} + diff --git a/src/sound_opl.h b/src/sound_opl.h new file mode 100644 index 000000000..9a03fda3a --- /dev/null +++ b/src/sound_opl.h @@ -0,0 +1,30 @@ +typedef struct opl_t +{ + int chip_nr[2]; + + int timers[2][2]; + int timers_enable[2][2]; + + int16_t filtbuf[2]; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} opl_t; + +uint8_t opl2_read(uint16_t a, void *priv); +void opl2_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl2_l_read(uint16_t a, void *priv); +void opl2_l_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl2_r_read(uint16_t a, void *priv); +void opl2_r_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl3_read(uint16_t a, void *priv); +void opl3_write(uint16_t a, uint8_t v, void *priv); + +void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); + +void opl2_init(opl_t *opl); +void opl3_init(opl_t *opl); + +void opl2_update2(opl_t *opl); +void opl3_update2(opl_t *opl); diff --git a/src/sound_pas16.c b/src/sound_pas16.c new file mode 100644 index 000000000..cc5a23538 --- /dev/null +++ b/src/sound_pas16.c @@ -0,0 +1,763 @@ +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "filters.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "sound.h" +#include "sound_opl.h" +#include "sound_pas16.h" +#include "sound_sb_dsp.h" +#include "timer.h" + +/* Original PAS uses + 2 x OPL2 + PIT - sample rate/count + LMC835N/LMC1982 - mixer + YM3802 - MIDI Control System + + + 9A01 - IO base + base >> 2 + + All below + IO base + + B89 - interrupt status / clear + bit 2 - sample rate + bit 3 - PCM + bit 4 - MIDI + + B88 - Audio mixer control register + + B8A - Audio filter control + bit 5 - mute? + + B8B - interrupt mask / board ID + bits 5-7 - board ID (read only on PAS16) + + F88 - PCM data (low) + + F89 - PCM data (high) + + F8A - PCM control? + bit 4 - input/output select (1 = output) + bit 5 - mono/stereo select + bit 6 - PCM enable + + 1388-138b - PIT clocked at 1193180 Hz + 1388 - sample rate + 1389 - sample count + + 178b - + 2789 - board revision + + 8389 - + bit 2 - 8/16 bit + + BF88 - wait states + + EF8B - + bit 3 - 16 bits okay ? + + F388 - + bit 6 - joystick enable + + F389 - + bits 0-2 - DMA + + F38A - + bits 0-3 - IRQ + + F788 - + bit 1 - SB emulation + bit 0 - MPU401 emulation + + F789 - SB base addr + bits 0-3 - addr bits 4-7 + + FB8A - SB IRQ/DMA + bits 3-5 - IRQ + bits 6-7 - DMA + + FF88 - board model + 3 = PAS16 +*/ + +typedef struct pas16_t +{ + uint16_t base; + + int irq, dma; + + uint8_t audiofilt; + + uint8_t audio_mixer; + + uint8_t compat, compat_base; + + uint8_t enhancedscsi; + + uint8_t io_conf_1, io_conf_2, io_conf_3, io_conf_4; + + uint8_t irq_stat, irq_ena; + + uint8_t pcm_ctrl; + uint16_t pcm_dat; + + uint16_t pcm_dat_l, pcm_dat_r; + + uint8_t sb_irqdma; + + int stereo_lr; + + uint8_t sys_conf_1, sys_conf_2, sys_conf_3, sys_conf_4; + + struct + { + uint32_t l[3]; + int c[3]; + uint8_t m[3]; + uint8_t ctrl, ctrls[2]; + int wp, rm[3], wm[3]; + uint16_t rl[3]; + int thit[3]; + int delay[3]; + int rereadlatch[3]; + int enable[3]; + } pit; + + opl_t opl; + sb_dsp_t dsp; + + int16_t pcm_buffer[2][SOUNDBUFLEN]; + + int pos; +} pas16_t; + +static uint8_t pas16_pit_in(uint16_t port, void *priv); +static void pas16_pit_out(uint16_t port, uint8_t val, void *priv); +static void pas16_update(pas16_t *pas16); + +static int pas16_dmas[8] = {4, 1, 2, 3, 0, 5, 6, 7}; +static int pas16_irqs[16] = {0, 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, 15, 0, 0, 0, 0}; +static int pas16_sb_irqs[8] = {0, 2, 3, 5, 7, 10, 11, 12}; +static int pas16_sb_dmas[8] = {0, 1, 2, 3}; + +enum +{ + PAS16_INT_SAMP = 0x04, + PAS16_INT_PCM = 0x08, +}; + +enum +{ + PAS16_PCM_MONO = 0x20, + PAS16_PCM_ENA = 0x40 +}; + +enum +{ + PAS16_SC2_16BIT = 0x04, + PAS16_SC2_MSBINV = 0x10 +}; + +enum +{ + PAS16_FILT_MUTE = 0x20 +}; + +static uint8_t pas16_in(uint16_t port, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + uint8_t temp; +/* if (CS == 0xCA53 && pc == 0x3AFC) + fatal("here");*/ + switch ((port - pas16->base) + 0x388) + { + case 0x388: case 0x389: case 0x38a: case 0x38b: + temp = opl3_read((port - pas16->base) + 0x388, &pas16->opl); + break; + + case 0xb88: + temp = pas16->audio_mixer; + break; + + case 0xb89: + temp = pas16->irq_stat; + break; + + case 0xb8a: + temp = pas16->audiofilt; + break; + + case 0xb8b: + temp = (pas16->irq_ena & ~0xe0) | 0x20; + break; + + case 0xf8a: + temp = pas16->pcm_ctrl; + break; + + case 0x1388: case 0x1389: case 0x138a: case 0x138b: + temp = pas16_pit_in(port, pas16); + break; + + case 0x2789: /*Board revision*/ + temp = 0; + break; + + case 0x7f89: + temp = pas16->enhancedscsi & ~1; + break; + + case 0x8388: + temp = pas16->sys_conf_1; + break; + case 0x8389: + temp = pas16->sys_conf_2; + break; + case 0x838b: + temp = pas16->sys_conf_3; + break; + case 0x838c: + temp = pas16->sys_conf_4; + break; + + case 0xef8b: + temp = 0x0c; + break; + + case 0xf388: + temp = pas16->io_conf_1; + break; + case 0xf389: + temp = pas16->io_conf_2; + break; + case 0xf38b: + temp = pas16->io_conf_3; + break; + case 0xf38c: + temp = pas16->io_conf_4; + break; + + case 0xf788: + temp = pas16->compat; + break; + case 0xf789: + temp = pas16->compat_base; + break; + + case 0xfb8a: + temp = pas16->sb_irqdma; + break; + + case 0xff88: /*Board model*/ + temp = 4; /*PAS16*/ + break; + case 0xff8b: /*Master mode read*/ + temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/ + break; + } +/* if (port != 0x388 && port != 0x389 && port != 0xb8b) */pclog("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,cpu_state.pc); +/* if (CS == 0x1FF4 && pc == 0x0585) + { + if (output) + fatal("here"); + output = 3; + }*/ + return temp; +} + +static void pas16_out(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; +/* if (port != 0x388 && port != 0x389) */pclog("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); +/* if (CS == 0x369 && pc == 0x2AC5) + fatal("here\n");*/ + switch ((port - pas16->base) + 0x388) + { + case 0x388: case 0x389: case 0x38a: case 0x38b: + opl3_write((port - pas16->base) + 0x388, val, &pas16->opl); + break; + + case 0xb88: + pas16->audio_mixer = val; + break; + + case 0xb89: + pas16->irq_stat &= ~val; +// pas16_update_irqs(); + break; + + case 0xb8a: + pas16_update(pas16); + pas16->audiofilt = val; + break; + + case 0xb8b: + pas16->irq_ena = val; +// pas16_update_irqs(); + break; + + case 0xf88: + pas16_update(pas16); + pas16->pcm_dat = (pas16->pcm_dat & 0xff00) | val; + break; + case 0xf89: + pas16_update(pas16); + pas16->pcm_dat = (pas16->pcm_dat & 0x00ff) | (val << 8); + break; + case 0xf8a: + if ((val & PAS16_PCM_ENA) && !(pas16->pcm_ctrl & PAS16_PCM_ENA)) /*Guess*/ + pas16->stereo_lr = 0; + pas16->pcm_ctrl = val; + break; + + case 0x1388: case 0x1389: case 0x138a: case 0x138b: + pas16_pit_out(port, val, pas16); + break; + + case 0x7f89: + pas16->enhancedscsi = val; + break; + + case 0x8388: + pas16->sys_conf_1 = val; + break; + case 0x8389: + pas16->sys_conf_2 = val; + break; + case 0x838a: + pas16->sys_conf_3 = val; + break; + case 0x838b: + pas16->sys_conf_4 = val; + break; + + case 0xf388: + pas16->io_conf_1 = val; + break; + case 0xf389: + pas16->io_conf_2 = val; + pas16->dma = pas16_dmas[val & 0x7]; + pclog("pas16_out : set PAS DMA %i\n", pas16->dma); + break; + case 0xf38a: + pas16->io_conf_3 = val; + pas16->irq = pas16_irqs[val & 0xf]; + pclog("pas16_out : set PAS IRQ %i\n", pas16->irq); + break; + case 0xf38b: + pas16->io_conf_4 = val; + break; + + case 0xf788: + pas16->compat = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + else + sb_dsp_setaddr(&pas16->dsp, 0); + break; + case 0xf789: + pas16->compat_base = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + break; + + case 0xfb8a: + pas16->sb_irqdma = val; + sb_dsp_setirq(&pas16->dsp, pas16_sb_irqs[(val >> 3) & 7]); + sb_dsp_setdma8(&pas16->dsp, pas16_sb_dmas[(val >> 6) & 3]); + pclog("pas16_out : set SB IRQ %i DMA %i\n", pas16_sb_irqs[(val >> 3) & 7], pas16_sb_dmas[(val >> 6) & 3]); + break; + + default: + pclog("pas16_out : unknown %04X\n", port); + } + if (cpu_state.pc == 0x80048CF3) + { + if (output) + fatal("here\n"); + output = 3; + } +/* if (CS == 0x1FF4 && pc == 0x0431) + output = 3;*/ +} + +static void pas16_pit_out(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + int t; + switch (port & 3) + { + case 3: /*CTRL*/ + if ((val & 0xC0) == 0xC0) + { + if (!(val & 0x20)) + { + if (val & 2) pas16->pit.rl[0] = pas16->pit.c[0] / (PITCONST * (1 << TIMER_SHIFT)); + if (val & 4) pas16->pit.rl[1] = pas16->pit.c[1]; + if (val & 8) pas16->pit.rl[2] = pas16->pit.c[2]; + } + return; + } + t = val >> 6; + pas16->pit.ctrls[t] = pas16->pit.ctrl = val; + if (t == 3) + { + printf("Bad PIT reg select\n"); + return; + } + if (!(pas16->pit.ctrl & 0x30)) + { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (!t) + pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); + if (pas16->pit.c[t] < 0) + pas16->pit.rl[t] = 0; + pas16->pit.ctrl |= 0x30; + pas16->pit.rereadlatch[t] = 0; + pas16->pit.rm[t] = 3; + } + else + { + pas16->pit.rm[t] = pas16->pit.wm[t] = (pas16->pit.ctrl >> 4) & 3; + pas16->pit.m[t] = (val >> 1) & 7; + if (pas16->pit.m[t] > 5) + pas16->pit.m[t] &= 3; + if (!pas16->pit.rm[t]) + { + pas16->pit.rm[t] = 3; + pas16->pit.rl[t] = pit.c[t]; + if (!t) + pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); + } + pas16->pit.rereadlatch[t] = 1; + } + pas16->pit.wp = 0; + pas16->pit.thit[t] = 0; + break; + case 0: case 1: case 2: /*Timers*/ + t = port & 3; + switch (pas16->pit.wm[t]) + { + case 1: + pas16->pit.l[t] = val; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.enable[t] = 1; + break; + case 2: + pas16->pit.l[t] = val << 8; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.enable[t] = 1; + break; + case 0: + pas16->pit.l[t] &= 0xFF; + pas16->pit.l[t] |= (val << 8); + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.thit[t] = 0; + pas16->pit.wm[t] = 3; + pas16->pit.enable[t] = 1; + break; + case 3: + pas16->pit.l[t] &= 0xFF00; + pas16->pit.l[t] |= val; + pas16->pit.wm[t] = 0; + break; + } + if (!pas16->pit.l[t]) + { + pas16->pit.l[t] |= 0x10000; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + } + break; + } +} + +static uint8_t pas16_pit_in(uint16_t port, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + uint8_t temp; + int t = port & 3; +// printf("Read PIT %04X ",addr); + switch (port & 3) + { + case 0: case 1: case 2: /*Timers*/ + if (pas16->pit.rereadlatch[t]) + { + pas16->pit.rereadlatch[t] = 0; + if (!t) + { + pas16->pit.rl[t] = pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT)); + if ((pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT))) > 65536) + pas16->pit.rl[t] = 0xFFFF; + } + else + { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (pas16->pit.c[t] > 65536) + pas16->pit.rl[t] = 0xFFFF; + } + } + switch (pas16->pit.rm[t]) + { + case 0: + temp = pas16->pit.rl[t] >> 8; + pas16->pit.rm[t] = 3; + pas16->pit.rereadlatch[t] = 1; + break; + case 1: + temp = (pas16->pit.rl[t]) & 0xFF; + pas16->pit.rereadlatch[t] = 1; + break; + case 2: + temp = (pas16->pit.rl[t]) >> 8; + pas16->pit.rereadlatch[t] = 1; + break; + case 3: + temp = (pas16->pit.rl[t]) & 0xFF; + if (pas16->pit.m[t] & 0x80) pas16->pit.m[t] &= 7; + else pas16->pit.rm[t] = 0; + break; + } + break; + case 3: /*Control*/ + temp = pas16->pit.ctrl; + break; + } +// printf("%02X %i %i %04X:%04X\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc); + return temp; +} + +static uint8_t pas16_readdma(pas16_t *pas16) +{ + return dma_channel_read(pas16->dma); +} + +static void pas16_pcm_poll(void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + pas16_update(pas16); +// if (pas16->pcm_ctrl & PAS16_PCM_ENA) +// pclog("pas16_pcm_poll : poll %i %i ", pas16->pit.c[0], pas16->pit.l[0]); + if (pas16->pit.m[0] & 2) + { + if (pas16->pit.l[0]) + pas16->pit.c[0] += (pas16->pit.l[0] * PITCONST * (1 << TIMER_SHIFT)); + else + pas16->pit.c[0] += (0x10000 * PITCONST * (1 << TIMER_SHIFT)); + } + else + { + pas16->pit.c[0] = -1; + pas16->pit.enable[0] = 0; + } +// if (pas16->pcm_ctrl & PAS16_PCM_ENA) +// pclog(" %i\n", pas16->pit.c[0]); + + pas16->irq_stat |= PAS16_INT_SAMP; + if (pas16->irq_ena & PAS16_INT_SAMP) + picint(1 << pas16->irq); +// pas16_update_irqs(); + + /*Update sample rate counter*/ + if (pas16->pit.enable[1]) + { + if (pas16->pcm_ctrl & PAS16_PCM_ENA) + { + uint16_t temp; + + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) + { + temp = pas16_readdma(pas16) << 8; + temp |= pas16_readdma(pas16); + } + else + temp = (pas16_readdma(pas16) ^ 0x80) << 8; + + if (pas16->sys_conf_2 & PAS16_SC2_MSBINV) + temp ^= 0x8000; + if (pas16->pcm_ctrl & PAS16_PCM_MONO) + pas16->pcm_dat_l = pas16->pcm_dat_r = temp; + else + { + if (pas16->stereo_lr) + pas16->pcm_dat_r = temp; + else + pas16->pcm_dat_l = temp; + + pas16->stereo_lr = !pas16->stereo_lr; + } +// pclog("pas16_pcm_poll : %04X %i\n", temp, pas16->stereo_lr); +// pclog("pas16_pcm_poll : %i %02X %i\n", pas16->pit.c[1], temp, pas16->pit.c[0]); +/* if (!pas16_pcm) + pas16_pcm=fopen("pas16->pcm", "wb"); + putc(temp, pas16_pcm);*/ + } + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) + pas16->pit.c[1] -= 2; + else + pas16->pit.c[1]--; + if (pas16->pit.c[1] == 0) + { +// if (pas16->pcm_ctrl & PAS16_PCM_ENA) +// pclog("pas16_pcm_poll : buffer over\n"); + if (pas16->pit.m[1] & 2) + { + if (pas16->pit.l[1]) + pas16->pit.c[1] += pas16->pit.l[1]; + else + pas16->pit.c[1] += 0x10000; + } + else + { + pas16->pit.c[1] = -1; + pas16->pit.enable[1] = 0; + } + + pas16->irq_stat |= PAS16_INT_PCM; + if (pas16->irq_ena & PAS16_INT_PCM) + { + pclog("pas16_pcm_poll : cause IRQ %i %02X\n", pas16->irq, 1 << pas16->irq); + picint(1 << pas16->irq); + } + } + } +} + +static void pas16_out_base(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + io_removehandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + + pas16->base = val << 2; + pclog("pas16_write_base : PAS16 base now at %04X\n", pas16->base); + + io_sethandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); +} + + +static void pas16_update(pas16_t *pas16) +{ + if (!(pas16->audiofilt & PAS16_FILT_MUTE)) + { + for (; pas16->pos < sound_pos_global; pas16->pos++) + { + pas16->pcm_buffer[0][pas16->pos] = 0; + pas16->pcm_buffer[1][pas16->pos] = 0; + } + } + else + { + for (; pas16->pos < sound_pos_global; pas16->pos++) + { + pas16->pcm_buffer[0][pas16->pos] = (int16_t)pas16->pcm_dat_l; + pas16->pcm_buffer[1][pas16->pos] = (int16_t)pas16->pcm_dat_r; + } + } +} + +void pas16_get_buffer(int32_t *buffer, int len, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + int c; + + opl3_update2(&pas16->opl); + sb_dsp_update(&pas16->dsp); + pas16_update(pas16); + for (c = 0; c < len * 2; c++) + { + buffer[c] += pas16->opl.buffer[c]; + buffer[c] += (int16_t)(sb_iir(c & 1, (float)pas16->dsp.buffer[c]) / 1.3) / 2; + buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2); + } + + pas16->pos = 0; + pas16->opl.pos = 0; + pas16->dsp.pos = 0; +} + +void *pas16_init() +{ + pas16_t *pas16 = malloc(sizeof(pas16_t)); + memset(pas16, 0, sizeof(pas16_t)); + + opl3_init(&pas16->opl); + sb_dsp_init(&pas16->dsp, SB2); + + io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); + + timer_add(pas16_pcm_poll, &pas16->pit.c[0], &pas16->pit.enable[0], pas16); + + sound_add_handler(pas16_get_buffer, pas16); + + return pas16; +} + +void pas16_close(void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + free(pas16); +} + +device_t pas16_device = +{ + "Pro Audio Spectrum 16", + DEVICE_NOT_WORKING, + pas16_init, + pas16_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_pas16.h b/src/sound_pas16.h new file mode 100644 index 000000000..e3a134751 --- /dev/null +++ b/src/sound_pas16.h @@ -0,0 +1 @@ +extern device_t pas16_device; diff --git a/src/sound_ps1.c b/src/sound_ps1.c new file mode 100644 index 000000000..4f42cd4d8 --- /dev/null +++ b/src/sound_ps1.c @@ -0,0 +1,174 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_ps1.h" +#include "sound_sn76489.h" + +typedef struct ps1_audio_t +{ + sn76489_t sn76489; + + uint8_t status, ctrl; + + int timer_latch, timer_count, timer_enable; + + uint8_t fifo[2048]; + int fifo_read_idx, fifo_write_idx; + int fifo_threshold; + + uint8_t dac_val; + + int16_t buffer[SOUNDBUFLEN]; + int pos; +} ps1_audio_t; + +static void ps1_update_irq_status(ps1_audio_t *ps1) +{ + if (((ps1->status & ps1->ctrl) & 0x12) && (ps1->ctrl & 0x01)) + picint(1 << 7); + else + picintc(1 << 7); +} + +static uint8_t ps1_audio_read(uint16_t port, void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + uint8_t temp; + +// pclog("ps1_audio_read %04x %04x:%04x\n", port, CS, pc); + + switch (port & 7) + { + case 0: /*ADC data*/ + ps1->status &= ~0x10; + ps1_update_irq_status(ps1); + return 0; + case 2: /*Status*/ + temp = ps1->status; + temp |= (ps1->ctrl & 0x01); + if ((ps1->fifo_write_idx - ps1->fifo_read_idx) >= 2048) + temp |= 0x08; /*FIFO full*/ + if (ps1->fifo_read_idx == ps1->fifo_write_idx) + temp |= 0x04; /*FIFO empty*/ +// pclog("Return status %02x\n", temp); + return temp; + case 3: /*FIFO timer*/ + /*PS/1 technical reference says this should return the current value, + but the PS/1 BIOS and Stunt Island expect it not to change*/ + return ps1->timer_latch; + case 4: case 5: case 6: case 7: + return 0; + } + return 0xff; +} + +static void ps1_audio_write(uint16_t port, uint8_t val, void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + +// pclog("ps1_audio_write %04x %02x\n", port, val); + + switch (port & 7) + { + case 0: /*DAC output*/ +// pclog("DAC write %08x %08x %i\n", ps1->fifo_write_idx, ps1->fifo_read_idx, ps1->fifo_write_idx - ps1->fifo_read_idx); + if ((ps1->fifo_write_idx - ps1->fifo_read_idx) < 2048) + { + ps1->fifo[ps1->fifo_write_idx & 2047] = val; + ps1->fifo_write_idx++; + } + break; + case 2: /*Control*/ + ps1->ctrl = val; + if (!(val & 0x02)) + ps1->status &= ~0x02; + ps1_update_irq_status(ps1); + break; + case 3: /*Timer reload value*/ + ps1->timer_latch = val; + ps1->timer_count = (0xff-val) * TIMER_USEC; + ps1->timer_enable = (val != 0); + break; + case 4: /*Almost empty*/ + ps1->fifo_threshold = val * 4; + break; + } +} + +static void ps1_audio_update(ps1_audio_t *ps1) +{ + for (; ps1->pos < sound_pos_global; ps1->pos++) + ps1->buffer[ps1->pos] = (int8_t)(ps1->dac_val ^ 0x80) * 0x20; +} + +static void ps1_audio_callback(void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + + ps1_audio_update(ps1); + + if (ps1->fifo_read_idx != ps1->fifo_write_idx) + { + ps1->dac_val = ps1->fifo[ps1->fifo_read_idx & 2047]; + ps1->fifo_read_idx++; + } +// pclog("ps1_callback %08x %08x %08x\n", ps1->fifo_write_idx, ps1->fifo_read_idx, ps1->fifo_threshold); + if ((ps1->fifo_write_idx - ps1->fifo_read_idx) == ps1->fifo_threshold) + { +// pclog("FIFO almost empty\n"); + ps1->status |= 0x02; /*FIFO almost empty*/ + } + ps1->status |= 0x10; /*ADC data ready*/ + ps1_update_irq_status(ps1); + + ps1->timer_count += ps1->timer_latch * TIMER_USEC; +} + +static void ps1_audio_get_buffer(int32_t *buffer, int len, void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + int c; + + ps1_audio_update(ps1); + + for (c = 0; c < len * 2; c++) + buffer[c] += ps1->buffer[c >> 1]; + + ps1->pos = 0; +} + +static void *ps1_audio_init() +{ + ps1_audio_t *ps1 = malloc(sizeof(ps1_audio_t)); + memset(ps1, 0, sizeof(ps1_audio_t)); + + sn76489_init(&ps1->sn76489, 0x0205, 0x0001, SN76496, 4000000); + + io_sethandler(0x0200, 0x0001, ps1_audio_read, NULL, NULL, ps1_audio_write, NULL, NULL, ps1); + io_sethandler(0x0202, 0x0006, ps1_audio_read, NULL, NULL, ps1_audio_write, NULL, NULL, ps1); + timer_add(ps1_audio_callback, &ps1->timer_count, &ps1->timer_enable, ps1); + sound_add_handler(ps1_audio_get_buffer, ps1); + + return ps1; +} + +static void ps1_audio_close(void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + + free(ps1); +} + +device_t ps1_audio_device = +{ + "PS/1 Audio Card", + 0, + ps1_audio_init, + ps1_audio_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_ps1.h b/src/sound_ps1.h new file mode 100644 index 000000000..04bb209d5 --- /dev/null +++ b/src/sound_ps1.h @@ -0,0 +1 @@ +extern device_t ps1_audio_device; diff --git a/src/sound_pssj.c b/src/sound_pssj.c new file mode 100644 index 000000000..0e4963d5d --- /dev/null +++ b/src/sound_pssj.c @@ -0,0 +1,214 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_pssj.h" +#include "sound_sn76489.h" + +#include "dma.h" +#include "pic.h" +#include "timer.h" + +typedef struct pssj_t +{ + sn76489_t sn76489; + + uint8_t ctrl; + uint8_t wave; + uint8_t dac_val; + uint16_t freq; + int amplitude; + + int irq; + int timer_count; + int enable; + + int wave_pos; + int pulse_width; + + int16_t buffer[SOUNDBUFLEN]; + int pos; +} pssj_t; + +static void pssj_update_irq(pssj_t *pssj) +{ + if (pssj->irq && (pssj->ctrl & 0x10) && (pssj->ctrl & 0x08)) + picint(1 << 7); +} + +static void pssj_write(uint16_t port, uint8_t val, void *p) +{ + pssj_t *pssj = (pssj_t *)p; + +// pclog("pssj_write: port=%04x val=%02x\n", port, val); + switch (port & 3) + { + case 0: + pssj->ctrl = val; + pssj->enable = (val & 4) && (pssj->ctrl & 3); + sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); + if (!(val & 8)) + pssj->irq = 0; + pssj_update_irq(pssj); + break; + case 1: + switch (pssj->ctrl & 3) + { + case 1: /*Sound channel*/ + pssj->wave = val; + pssj->pulse_width = val & 7; + break; + case 3: /*Direct DAC*/ + pssj->dac_val = val; + break; + } + break; + case 2: + pssj->freq = (pssj->freq & 0xf00) | val; + break; + case 3: + pssj->freq = (pssj->freq & 0x0ff) | ((val & 0xf) << 8); + pssj->amplitude = val >> 4; + break; + } +} +static uint8_t pssj_read(uint16_t port, void *p) +{ + pssj_t *pssj = (pssj_t *)p; + +// pclog("pssj_read: port=%04x %02x\n", port, (pssj->ctrl & ~0x88) | (pssj->irq ? 8 : 0)); + switch (port & 3) + { + case 0: + return (pssj->ctrl & ~0x88) | (pssj->irq ? 8 : 0); + case 1: + switch (pssj->ctrl & 3) + { + case 0: /*Joystick*/ + return 0; + case 1: /*Sound channel*/ + return pssj->wave; + case 2: /*Successive approximation*/ + return 0x80; + case 3: /*Direct DAC*/ + return pssj->dac_val; + } + break; + case 2: + return pssj->freq & 0xff; + case 3: + return (pssj->freq >> 8) | (pssj->amplitude << 4); + } +} + +static void pssj_update(pssj_t *pssj) +{ + for (; pssj->pos < sound_pos_global; pssj->pos++) + pssj->buffer[pssj->pos] = (((int8_t)(pssj->dac_val ^ 0x80) * 0x20) * pssj->amplitude) / 15; +} + +static void pssj_callback(void *p) +{ + pssj_t *pssj = (pssj_t *)p; + int data; + + pssj_update(pssj); + if (pssj->ctrl & 2) + { + if ((pssj->ctrl & 3) == 3) + { + data = dma_channel_read(1); + + if (data != DMA_NODATA) + { + pssj->dac_val = data & 0xff; +// pclog("DAC_val=%02x\n", data); + } + } + else + { + data = dma_channel_write(1, 0x80); + } + + if ((data & DMA_OVER) && data != DMA_NODATA) + { +// pclog("Check IRQ %i %02x\n", pssj->irq, pssj->ctrl); + if (pssj->ctrl & 0x08) + { + pssj->irq = 1; + pssj_update_irq(pssj); + } + } + } + else + { + switch (pssj->wave & 0xc0) + { + case 0x00: /*Pulse*/ + pssj->dac_val = (pssj->wave_pos > (pssj->pulse_width << 1)) ? 0xff : 0; + break; + case 0x40: /*Ramp*/ + pssj->dac_val = pssj->wave_pos << 3; + break; + case 0x80: /*Triangle*/ + if (pssj->wave_pos & 16) + pssj->dac_val = (pssj->wave_pos ^ 31) << 4; + else + pssj->dac_val = pssj->wave_pos << 4; + break; + case 0xc0: + pssj->dac_val = 0x80; + break; + } + pssj->wave_pos = (pssj->wave_pos + 1) & 31; + } + + pssj->timer_count += (int)(TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400)); +} + +static void pssj_get_buffer(int32_t *buffer, int len, void *p) +{ + pssj_t *pssj = (pssj_t *)p; + int c; + + pssj_update(pssj); + + for (c = 0; c < len * 2; c++) + buffer[c] += pssj->buffer[c >> 1]; + + pssj->pos = 0; +} + +void *pssj_init() +{ + pssj_t *pssj = malloc(sizeof(pssj_t)); + memset(pssj, 0, sizeof(pssj_t)); + + sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ, 3579545); + + io_sethandler(0x00C4, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj); + timer_add(pssj_callback, &pssj->timer_count, &pssj->enable, pssj); + sound_add_handler(pssj_get_buffer, pssj); + + return pssj; +} + +void pssj_close(void *p) +{ + pssj_t *pssj = (pssj_t *)p; + + free(pssj); +} + +device_t pssj_device = +{ + "Tandy PSSJ", + 0, + pssj_init, + pssj_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_pssj.h b/src/sound_pssj.h new file mode 100644 index 000000000..2255d48fb --- /dev/null +++ b/src/sound_pssj.h @@ -0,0 +1 @@ +extern device_t pssj_device; diff --git a/src/sound_resid.cc b/src/sound_resid.cc new file mode 100644 index 000000000..8185b6046 --- /dev/null +++ b/src/sound_resid.cc @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include "resid-fp/sid.h" +#include "sound_resid.h" + +typedef struct psid_t +{ + /* resid sid implementation */ + SIDFP *sid; + int16_t last_sample; +} psid_t; + +psid_t *psid; + +void *sid_init() +{ +// psid_t *psid; + int c; + sampling_method method=SAMPLE_INTERPOLATE; + float cycles_per_sec = 14318180.0 / 16.0; + + psid = new psid_t; +// psid = (psid_t *)malloc(sizeof(sound_t)); + psid->sid = new SIDFP; + + psid->sid->set_chip_model(MOS8580FP); + + psid->sid->set_voice_nonlinearity(1.0f); + psid->sid->get_filter().set_distortion_properties(0.f, 0.f, 0.f); + psid->sid->get_filter().set_type4_properties(6.55f, 20.0f); + + psid->sid->enable_filter(true); + psid->sid->enable_external_filter(true); + + psid->sid->reset(); + + for (c=0;c<32;c++) + psid->sid->write(c,0); + + if (!psid->sid->set_sampling_parameters((float)cycles_per_sec, method, + (float)48000, 0.9*48000.0/2.0)) + { + // printf("reSID failed!\n"); + } + + psid->sid->set_chip_model(MOS6581FP); + psid->sid->set_voice_nonlinearity(0.96f); + psid->sid->get_filter().set_distortion_properties(3.7e-3f, 2048.f, 1.2e-4f); + + psid->sid->input(0); + psid->sid->get_filter().set_type3_properties(1.33e6f, 2.2e9f, 1.0056f, 7e3f); + + return (void *)psid; +} + +void sid_close(void *p) +{ +// psid_t *psid = (psid_t *)p; + delete psid->sid; +// free(psid); +} + +void sid_reset(void *p) +{ +// psid_t *psid = (psid_t *)p; + int c; + + psid->sid->reset(); + + for (c = 0; c < 32; c++) + psid->sid->write(c, 0); +} + + +uint8_t sid_read(uint16_t addr, void *p) +{ +// psid_t *psid = (psid_t *)p; + + return psid->sid->read(addr & 0x1f); +// return 0xFF; +} + +void sid_write(uint16_t addr, uint8_t val, void *p) +{ +// psid_t *psid = (psid_t *)p; + + psid->sid->write(addr & 0x1f,val); +} + +#define CLOCK_DELTA(n) (int)(((14318180.0 * n) / 16.0) / 48000.0) + +static void fillbuf2(int& count, int16_t *buf, int len) +{ + int c; + c = psid->sid->clock(count, buf, len, 1); + if (!c) + *buf = psid->last_sample; + psid->last_sample = *buf; +} +void sid_fillbuf(int16_t *buf, int len, void *p) +{ +// psid_t *psid = (psid_t *)p; + int x = CLOCK_DELTA(len); + + fillbuf2(x, buf, len); +} diff --git a/src/sound_resid.h b/src/sound_resid.h new file mode 100644 index 000000000..402ee0ceb --- /dev/null +++ b/src/sound_resid.h @@ -0,0 +1,12 @@ +#ifdef __cplusplus +extern "C" { +#endif + void *sid_init(); + void sid_close(void *p); + void sid_reset(void *p); + uint8_t sid_read(uint16_t addr, void *p); + void sid_write(uint16_t addr, uint8_t val, void *p); + void sid_fillbuf(int16_t *buf, int len, void *p); +#ifdef __cplusplus +} +#endif diff --git a/src/sound_sb.c b/src/sound_sb.c new file mode 100644 index 000000000..34ca8b4d7 --- /dev/null +++ b/src/sound_sb.c @@ -0,0 +1,840 @@ +#include +#include "ibm.h" +#include "device.h" +#include "sound_emu8k.h" +#include "sound_mpu401_uart.h" +#include "sound_opl.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" + +#include "filters.h" + +typedef struct sb_mixer_t +{ + int master_l, master_r; + int voice_l, voice_r; + int fm_l, fm_r; + int cd_l, cd_r; + int bass_l, bass_r; + int treble_l, treble_r; + int filter; + + int index; + uint8_t regs[256]; +} sb_mixer_t; + +typedef struct sb_t +{ + opl_t opl; + sb_dsp_t dsp; + sb_mixer_t mixer; + mpu401_uart_t mpu; + emu8k_t emu8k; + + int pos; +} sb_t; + +static int sb_att[]= +{ + 310,368,437,520,618,735,873,1038,1234,1467,1743,2072,2463,2927,3479, + 4134,4914,5840,6941,8250,9805,11653,13850,16461,19564,23252,27635,32845, + 39036,46395,55140,65535 +}; + +static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + int c; + + opl2_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) + { + int32_t out_l, out_r; + + out_l = ((sb->opl.buffer[c] * mixer->fm_l) >> 16); + out_r = ((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16); + + if (sb->mixer.filter) + { + out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; + out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; + } + else + { + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; + } + + out_l = (out_l * mixer->master_l) >> 16; + out_r = (out_r * mixer->master_r) >> 16; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5; + if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5; + if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5; + if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5; + if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5; + if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5; + if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5; + if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5; + } + + buffer[c] += out_l; + buffer[c + 1] += out_r; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +} + +static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + int c; + + opl3_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) + { + int c_emu8k = (((c/2) * 44100) / 48000)*2; + int32_t out_l, out_r; + + out_l = ((sb->opl.buffer[c] * mixer->fm_l) >> 16); + out_r = ((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16); + + if (sb->mixer.filter) + { + out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; + out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; + } + else + { + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; + } + + out_l = (out_l * mixer->master_l) >> 16; + out_r = (out_r * mixer->master_r) >> 16; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5; + if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5; + if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5; + if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5; + if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5; + if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5; + if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5; + if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5; + } + + buffer[c] += out_l; + buffer[c + 1] += out_r; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; + sb->emu8k.pos = 0; +} + +static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + int c; + + opl3_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + emu8k_update(&sb->emu8k); + for (c = 0; c < len * 2; c += 2) + { + int c_emu8k = (((c/2) * 44100) / 48000)*2; + int32_t out_l, out_r; + + out_l = (((int32_t)sb->opl.buffer[c] * (int32_t)mixer->fm_l) >> 16); + out_r = (((int32_t)sb->opl.buffer[c + 1] * (int32_t)mixer->fm_r) >> 16); + + out_l += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 16); + out_r += ((sb->emu8k.buffer[c_emu8k + 1] * mixer->fm_l) >> 16); + + if (sb->mixer.filter) + { + out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; + out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; + } + else + { + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; + } + + out_l = (out_l * mixer->master_l) >> 16; + out_r = (out_r * mixer->master_r) >> 16; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5; + if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5; + if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5; + if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5; + if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5; + if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5; + if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5; + if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5; + } + + buffer[c] += out_l; + buffer[c + 1] += out_r; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; + sb->emu8k.pos = 0; +} + +void sb_pro_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + mixer->index = val & 0xff; + else + { + mixer->regs[mixer->index] = val; + + mixer->master_l = sb_att[(mixer->regs[0x22] >> 4) | 0x11]; + mixer->master_r = sb_att[(mixer->regs[0x22] & 0xf) | 0x11]; + mixer->voice_l = sb_att[(mixer->regs[0x04] >> 4) | 0x11]; + mixer->voice_r = sb_att[(mixer->regs[0x04] & 0xf) | 0x11]; + mixer->fm_l = sb_att[(mixer->regs[0x26] >> 4) | 0x11]; + mixer->fm_r = sb_att[(mixer->regs[0x26] & 0xf) | 0x11]; + mixer->cd_l = sb_att[(mixer->regs[0x28] >> 4) | 0x11]; + mixer->cd_r = sb_att[(mixer->regs[0x28] & 0xf) | 0x11]; + mixer->filter = !(mixer->regs[0xe] & 0x20); + mixer->bass_l = mixer->bass_r = 8; + mixer->treble_l = mixer->treble_r = 8; + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); +// pclog("%02X %02X %02X\n", mixer->regs[0x04], mixer->regs[0x22], mixer->regs[0x26]); +// pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r); + if (mixer->index == 0xe) + sb_dsp_set_stereo(&sb->dsp, val & 2); + } +} + +uint8_t sb_pro_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + return mixer->index; + + return mixer->regs[mixer->index]; +} + +void sb_16_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + mixer->index = val; + else + { + mixer->regs[mixer->index] = val; + switch (mixer->index) + { + case 0x22: + mixer->regs[0x30] = ((mixer->regs[0x22] >> 4) | 0x11) << 3; + mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) | 0x11) << 3; + break; + case 0x04: + mixer->regs[0x32] = ((mixer->regs[0x04] >> 4) | 0x11) << 3; + mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) | 0x11) << 3; + break; + case 0x26: + mixer->regs[0x34] = ((mixer->regs[0x26] >> 4) | 0x11) << 3; + mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) | 0x11) << 3; + break; + case 0x28: + mixer->regs[0x36] = ((mixer->regs[0x28] >> 4) | 0x11) << 3; + mixer->regs[0x37] = ((mixer->regs[0x28] & 0xf) | 0x11) << 3; + break; + case 0x80: + if (val & 1) sb->dsp.sb_irqnum = 2; + if (val & 2) sb->dsp.sb_irqnum = 5; + if (val & 4) sb->dsp.sb_irqnum = 7; + if (val & 8) sb->dsp.sb_irqnum = 10; + break; + } + mixer->master_l = sb_att[mixer->regs[0x30] >> 3]; + mixer->master_r = sb_att[mixer->regs[0x31] >> 3]; + mixer->voice_l = sb_att[mixer->regs[0x32] >> 3]; + mixer->voice_r = sb_att[mixer->regs[0x33] >> 3]; + mixer->fm_l = sb_att[mixer->regs[0x34] >> 3]; + mixer->fm_r = sb_att[mixer->regs[0x35] >> 3]; + mixer->cd_l = sb_att[mixer->regs[0x36] >> 3]; + mixer->cd_r = sb_att[mixer->regs[0x37] >> 3]; + mixer->bass_l = mixer->regs[0x46] >> 4; + mixer->bass_r = mixer->regs[0x47] >> 4; + mixer->treble_l = mixer->regs[0x44] >> 4; + mixer->treble_r = mixer->regs[0x45] >> 4; + mixer->filter = 0; + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); +// pclog("%02X %02X %02X %02X %02X %02X\n", mixer->regs[0x30], mixer->regs[0x31], mixer->regs[0x32], mixer->regs[0x33], mixer->regs[0x34], mixer->regs[0x35]); +// pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r); + } +} + +uint8_t sb_16_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + return mixer->index; + + switch (mixer->index) + { + case 0x80: + switch (sb->dsp.sb_irqnum) + { + case 2: return 1; /*IRQ 7*/ + case 5: return 2; /*IRQ 7*/ + case 7: return 4; /*IRQ 7*/ + case 10: return 8; /*IRQ 7*/ + } + break; + case 0x81: + return 0x22; /*DMA 1 and 5*/ + case 0x82: + return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0); + } + return mixer->regs[mixer->index]; +} + +void sb_mixer_init(sb_mixer_t *mixer) +{ + mixer->master_l = mixer->master_r = 65535; + mixer->voice_l = mixer->voice_r = 65535; + mixer->fm_l = mixer->fm_r = 65535; + mixer->bass_l = mixer->bass_r = 8; + mixer->treble_l = mixer->treble_r = 8; + mixer->filter = 1; +} + +void *sb_1_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB1); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_get_buffer_opl2, sb); + return sb; +} +void *sb_15_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB15); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_get_buffer_opl2, sb); + return sb; +} +void *sb_2_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB2); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_get_buffer_opl2, sb); + return sb; +} + +void *sb_pro_v1_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+0, 0x0002, opl2_l_read, NULL, NULL, opl2_l_write, NULL, NULL, &sb->opl); + io_sethandler(addr+2, 0x0002, opl2_r_read, NULL, NULL, opl2_r_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_opl2, sb); + + sb->mixer.regs[0x22] = 0xff; + sb->mixer.regs[0x04] = 0xff; + sb->mixer.regs[0x26] = 0xff; + sb->mixer.regs[0xe] = 0; + + return sb; +} + +void *sb_pro_v2_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO2); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_opl3, sb); + + sb->mixer.regs[0x22] = 0xff; + sb->mixer.regs[0x04] = 0xff; + sb->mixer.regs[0x26] = 0xff; + sb->mixer.regs[0xe] = 0; + + return sb; +} + +void *sb_16_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB16); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_opl3, sb); + mpu401_uart_init(&sb->mpu, 0x330); + + sb->mixer.regs[0x30] = 31 << 3; + sb->mixer.regs[0x31] = 31 << 3; + sb->mixer.regs[0x32] = 31 << 3; + sb->mixer.regs[0x33] = 31 << 3; + sb->mixer.regs[0x34] = 31 << 3; + sb->mixer.regs[0x35] = 31 << 3; + sb->mixer.regs[0x44] = 8 << 4; + sb->mixer.regs[0x45] = 8 << 4; + sb->mixer.regs[0x46] = 8 << 4; + sb->mixer.regs[0x47] = 8 << 4; + sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4); + sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4); + sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4); + + return sb; +} + +int sb_awe32_available() +{ + return rom_present("roms/awe32.raw"); +} + +void *sb_awe32_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + int onboard_ram = device_get_config_int("onboard_ram"); + memset(sb, 0, sizeof(sb_t)); + + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB16 + 1); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_emu8k, sb); + mpu401_uart_init(&sb->mpu, 0x330); + emu8k_init(&sb->emu8k, onboard_ram); + + sb->mixer.regs[0x30] = 31 << 3; + sb->mixer.regs[0x31] = 31 << 3; + sb->mixer.regs[0x32] = 31 << 3; + sb->mixer.regs[0x33] = 31 << 3; + sb->mixer.regs[0x34] = 31 << 3; + sb->mixer.regs[0x35] = 31 << 3; + sb->mixer.regs[0x44] = 8 << 4; + sb->mixer.regs[0x45] = 8 << 4; + sb->mixer.regs[0x46] = 8 << 4; + sb->mixer.regs[0x47] = 8 << 4; + sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4); + sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4); + sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4); + + return sb; +} + +void sb_close(void *p) +{ + sb_t *sb = (sb_t *)p; + + free(sb); +} + +void sb_awe32_close(void *p) +{ + sb_t *sb = (sb_t *)p; + + emu8k_close(&sb->emu8k); + + free(sb); +} + +void sb_speed_changed(void *p) +{ + sb_t *sb = (sb_t *)p; + + sb_dsp_speed_changed(&sb->dsp); +} + +void sb_add_status_info(char *s, int max_len, void *p) +{ + sb_t *sb = (sb_t *)p; + + sb_dsp_add_status_info(s, max_len, &sb->dsp); +} + +static device_config_t sb_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "" + } + }, + .default_int = 0x220 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { + .description = "" + } + }, + .default_int = 1 + }, + { + .type = -1 + } +}; + +static device_config_t sb_pro_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "" + } + }, + .default_int = 0x220 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { + .description = "" + } + }, + .default_int = 1 + }, + { + .type = -1 + } +}; + +static device_config_t sb_16_config[] = +{ + { + .name = "midi", + .description = "MIDI out device", + .type = CONFIG_MIDI, + .default_int = 0 + }, + { + .type = -1 + } +}; + +static device_config_t sb_awe32_config[] = +{ + { + .name = "midi", + .description = "MIDI out device", + .type = CONFIG_MIDI, + .default_int = 0 + }, + { + .name = "onboard_ram", + .description = "Onboard RAM", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "None", + .value = 0 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "8 MB", + .value = 8192 + }, + { + .description = "28 MB", + .value = 28*1024 + }, + { + .description = "" + } + }, + .default_int = 512 + }, + { + .type = -1 + } +}; + +device_t sb_1_device = +{ + "Sound Blaster v1.0", + 0, + sb_1_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_config +}; +device_t sb_15_device = +{ + "Sound Blaster v1.5", + 0, + sb_15_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_config +}; +device_t sb_2_device = +{ + "Sound Blaster v2.0", + 0, + sb_2_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_config +}; +device_t sb_pro_v1_device = +{ + "Sound Blaster Pro v1", + 0, + sb_pro_v1_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_pro_config +}; +device_t sb_pro_v2_device = +{ + "Sound Blaster Pro v2", + 0, + sb_pro_v2_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_pro_config +}; +device_t sb_16_device = +{ + "Sound Blaster 16", + 0, + sb_16_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_16_config +}; +device_t sb_awe32_device = +{ + "Sound Blaster AWE32", + 0, + sb_awe32_init, + sb_close, + sb_awe32_available, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_awe32_config +}; diff --git a/src/sound_sb.h b/src/sound_sb.h new file mode 100644 index 000000000..81130fecd --- /dev/null +++ b/src/sound_sb.h @@ -0,0 +1,7 @@ +extern device_t sb_1_device; +extern device_t sb_15_device; +extern device_t sb_2_device; +extern device_t sb_pro_v1_device; +extern device_t sb_pro_v2_device; +extern device_t sb_16_device; +extern device_t sb_awe32_device; diff --git a/src/sound_sb_dsp.c b/src/sound_sb_dsp.c new file mode 100644 index 000000000..dc4013c1c --- /dev/null +++ b/src/sound_sb_dsp.c @@ -0,0 +1,1013 @@ +/*Jazz sample rates : + 386-33 - 12kHz + 486-33 - 20kHz + 486-50 - 32kHz + Pentium - 45kHz*/ + +#include +#include +#include "ibm.h" + + +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "sound.h" +#include "sound_sb_dsp.h" +#include "timer.h" + +void pollsb(void *p); +void sb_poll_i(void *p); + + + +static int sbe2dat[4][9] = { + { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, + { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 }, + { -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 }, + { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 } +}; + +static int sb_commands[256]= +{ + -1, 2,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1, + 1,-1,-1,-1, 2,-1, 2, 2,-1,-1,-1,-1, 0,-1,-1, 0, + 0,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 1, 2, 2,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,-1, 0,-1, 0, + 2, 2,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1, + 0,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1,-1,-1,-1, + 1, 0, 1, 0, 1,-1,-1, 0, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0 +}; + +char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; +uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x40d}; + +/*These tables were 'borrowed' from DOSBox*/ + int8_t scaleMap4[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, + 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, + 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, + 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 + }; + uint8_t adjustMap4[64] = { + 0, 0, 0, 0, 0, 16, 16, 16, + 0, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 0 + }; + + int8_t scaleMap26[40] = { + 0, 1, 2, 3, 0, -1, -2, -3, + 1, 3, 5, 7, -1, -3, -5, -7, + 2, 6, 10, 14, -2, -6, -10, -14, + 4, 12, 20, 28, -4, -12, -20, -28, + 5, 15, 25, 35, -5, -15, -25, -35 + }; + uint8_t adjustMap26[40] = { + 0, 0, 0, 8, 0, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 0, 248, 0, 0, 0 + }; + + int8_t scaleMap2[24] = { + 0, 1, 0, -1, 1, 3, -1, -3, + 2, 6, -2, -6, 4, 12, -4, -12, + 8, 24, -8, -24, 6, 48, -16, -48 + }; + uint8_t adjustMap2[24] = { + 0, 4, 0, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 0, 252, 0 + }; + + + +void sb_irq(sb_dsp_t *dsp, int irq8) +{ +// pclog("IRQ %i %02X\n",irq8,pic.mask); + if (irq8) dsp->sb_irq8 = 1; + else dsp->sb_irq16 = 1; + picint(1 << dsp->sb_irqnum); +} +void sb_irqc(sb_dsp_t *dsp, int irq8) +{ + if (irq8) dsp->sb_irq8 = 0; + else dsp->sb_irq16 = 0; + picintc(1 << dsp->sb_irqnum); +} + +void sb_dsp_reset(sb_dsp_t *dsp) +{ + dsp->sbenable = dsp->sb_enable_i = 0; + dsp->sb_command = 0; + + dsp->sb_8_length = 0xffff; + dsp->sb_8_autolen = 0xffff; + + sb_irqc(dsp, 0); + sb_irqc(dsp, 1); + dsp->sb_16_pause = 0; + dsp->sb_read_wp = dsp->sb_read_rp = 0; + dsp->sb_data_stat = -1; + dsp->sb_speaker = 0; + dsp->sb_pausetime = -1; + dsp->sbe2 = 0xAA; + dsp->sbe2count = 0; + + dsp->sbreset = 0; + dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0; + + picintc(1 << dsp->sb_irqnum); + + dsp->asp_data_len = 0; +} + +void sb_doreset(sb_dsp_t *dsp) +{ + int c; + + sb_dsp_reset(dsp); + + if (dsp->sb_type==SB16) sb_commands[8] = 1; + else sb_commands[8] = -1; + + for (c = 0; c < 256; c++) + dsp->sb_asp_regs[c] = 0; + dsp->sb_asp_regs[5] = 0x01; + dsp->sb_asp_regs[9] = 0xf8; +} + +void sb_dsp_speed_changed(sb_dsp_t *dsp) +{ + if (dsp->sb_timeo < 256) + dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo); + else + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256))); + + if (dsp->sb_timei < 256) + dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei); + else + dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256))); +} + +void sb_add_data(sb_dsp_t *dsp, uint8_t v) +{ + dsp->sb_read_data[dsp->sb_read_wp++] = v; + dsp->sb_read_wp &= 0xff; +} + +#define ADPCM_4 1 +#define ADPCM_26 2 +#define ADPCM_2 3 + +void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) +{ + dsp->sb_pausetime = -1; + if (dma8) + { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && dsp->sb_16_output) dsp->sb_16_enable = 0; + dsp->sb_8_output = 1; + timer_process(); + dsp->sbenable = dsp->sb_8_enable; + timer_update_outstanding(); + dsp->sbleftright = 0; + dsp->sbdacpos = 0; +// pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } + else + { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0; + dsp->sb_16_output = 1; + timer_process(); + dsp->sbenable = dsp->sb_16_enable; + timer_update_outstanding(); +// pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len); + } +} + +void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) +{ + if (dma8) + { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && !dsp->sb_16_output) dsp->sb_16_enable = 0; + dsp->sb_8_output = 0; + timer_process(); + dsp->sb_enable_i = dsp->sb_8_enable; + timer_update_outstanding(); +// pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } + else + { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && !dsp->sb_8_output) dsp->sb_8_enable = 0; + dsp->sb_16_output = 0; + timer_process(); + dsp->sb_enable_i = dsp->sb_16_enable; + timer_update_outstanding(); +// pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } +} + +int sb_8_read_dma(sb_dsp_t *dsp) +{ + return dma_channel_read(dsp->sb_8_dmanum); +} +void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) +{ + dma_channel_write(dsp->sb_8_dmanum, val); +} +uint16_t sb_16_read_dma(sb_dsp_t *dsp) +{ + return dma_channel_read(5); +} +void sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) +{ + dma_channel_write(5, val); +} + +void sb_dsp_setirq(sb_dsp_t *dsp, int irq) +{ + dsp->sb_irqnum = irq; +} + +void sb_dsp_setdma8(sb_dsp_t *dsp, int dma) +{ + dsp->sb_8_dmanum = dma; +} + +void sb_exec_command(sb_dsp_t *dsp) +{ + int temp,c; +// pclog("sb_exec_command : SB command %02X\n", dsp->sb_command); + switch (dsp->sb_command) + { + case 0x01: /*???*/ + if (dsp->sb_type < SB16) break; + dsp->asp_data_len = dsp->sb_data[0] + (dsp->sb_data[1] << 8) + 1; + break; + case 0x03: /*ASP status*/ + sb_add_data(dsp, 0); + break; + case 0x10: /*8-bit direct mode*/ + sb_dsp_update(dsp); + dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8; + break; + case 0x14: /*8-bit single cycle DMA output*/ + sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x17: /*2-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; +// pclog("Ref byte 2 %02X\n",sbref); + case 0x16: /*2-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x1C: /*8-bit autoinit DMA output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x1F: /*2-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x20: /*8-bit direct input*/ + sb_add_data(dsp, 0); + break; + case 0x24: /*8-bit single cycle DMA input*/ + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x2C: /*8-bit autoinit DMA input*/ + if (dsp->sb_type < SB15) break; + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x40: /*Set time constant*/ + dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0]; + dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); + temp = 256 - dsp->sb_data[0]; + temp = 1000000 / temp; +// pclog("Sample rate - %ihz (%i)\n",temp, dsp->sblatcho); + dsp->sb_freq = temp; + break; + case 0x41: /*Set output sampling rate*/ + case 0x42: /*Set input sampling rate*/ + if (dsp->sb_type < SB16) break; + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); +// pclog("Sample rate - %ihz (%i)\n",dsp->sb_data[1]+(dsp->sb_data[0]<<8), dsp->sblatcho); + dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8); + dsp->sb_timeo = 256 + dsp->sb_freq; + dsp->sblatchi = dsp->sblatcho; + dsp->sb_timei = dsp->sb_timeo; + break; + case 0x48: /*Set DSP block transfer size*/ + dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8); + break; + case 0x75: /*4-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; +// pclog("Ref byte 4 %02X\n",sbref); + case 0x74: /*4-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x77: /*2.6-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; +// pclog("Ref byte 26 %02X\n",sbref); + case 0x76: /*2.6-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x7D: /*4-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x7F: /*2.6-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x80: /*Pause DAC*/ + dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); +// pclog("SB pause %04X\n",sb_pausetime); + timer_process(); + dsp->sbenable = 1; + timer_update_outstanding(); + break; + case 0x90: /*High speed 8-bit autoinit DMA output*/ + if (dsp->sb_type < SB2) break; + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x91: /*High speed 8-bit single cycle DMA output*/ + if (dsp->sb_type < SB2) break; + sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0x98: /*High speed 8-bit autoinit DMA input*/ + if (dsp->sb_type < SB2) break; + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x99: /*High speed 8-bit single cycle DMA input*/ + if (dsp->sb_type < SB2) break; + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0xA0: /*Set input mode to mono*/ + case 0xA8: /*Set input mode to stereo*/ + break; + case 0xB0: case 0xB1: case 0xB2: case 0xB3: + case 0xB4: case 0xB5: case 0xB6: case 0xB7: /*16-bit DMA output*/ + if (dsp->sb_type < SB16) break; + sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: + case 0xBC: case 0xBD: case 0xBE: case 0xBF: /*16-bit DMA input*/ + if (dsp->sb_type < SB16) break; + sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC4: case 0xC5: case 0xC6: case 0xC7: /*8-bit DMA output*/ + if (dsp->sb_type < SB16) break; + sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + case 0xCC: case 0xCD: case 0xCE: case 0xCF: /*8-bit DMA input*/ + if (dsp->sb_type < SB16) break; + sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xD0: /*Pause 8-bit DMA*/ + dsp->sb_8_pause = 1; + break; + case 0xD1: /*Speaker on*/ + dsp->sb_speaker = 1; + break; + case 0xD3: /*Speaker off*/ + dsp->sb_speaker = 0; + break; + case 0xD4: /*Continue 8-bit DMA*/ + dsp->sb_8_pause = 0; + break; + case 0xD5: /*Pause 16-bit DMA*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_pause = 1; + break; + case 0xD6: /*Continue 16-bit DMA*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_pause = 0; + break; + case 0xD8: /*Get speaker status*/ + sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0); + break; + case 0xD9: /*Exit 16-bit auto-init mode*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_autoinit = 0; + break; + case 0xDA: /*Exit 8-bit auto-init mode*/ + dsp->sb_8_autoinit = 0; + break; + case 0xE0: /*DSP identification*/ + sb_add_data(dsp, ~dsp->sb_data[0]); + break; + case 0xE1: /*Get DSP version*/ + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); + break; + case 0xE2: /*Stupid ID/protection*/ + for (c = 0; c < 8; c++) + if (dsp->sb_data[0] & (1 << c)) dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c]; + dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8]; + dsp->sbe2count++; + sb_8_write_dma(dsp, dsp->sbe2); + break; + case 0xE3: /*DSP copyright*/ + if (dsp->sb_type < SB16) break; + c = 0; + while (sb16_copyright[c]) + sb_add_data(dsp, sb16_copyright[c++]); + sb_add_data(dsp, 0); + break; + case 0xE4: /*Write test register*/ + dsp->sb_test = dsp->sb_data[0]; + break; + case 0xE8: /*Read test register*/ + sb_add_data(dsp, dsp->sb_test); + break; + case 0xF2: /*Trigger 8-bit IRQ*/ +// pclog("Trigger IRQ\n"); + sb_irq(dsp, 1); + break; + case 0xE7: /*???*/ + case 0xFA: /*???*/ + break; + case 0x07: /*No, that's not how you program auto-init DMA*/ + case 0xFF: + break; + case 0x08: /*ASP get version*/ + if (dsp->sb_type < SB16) break; + sb_add_data(dsp, 0x18); + break; + case 0x0E: /*ASP set register*/ + if (dsp->sb_type < SB16) break; + dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; +// pclog("ASP write reg %02X %02X\n", sb_data[0], sb_data[1]); + break; + case 0x0F: /*ASP get register*/ + if (dsp->sb_type < SB16) break; +// sb_add_data(0); + sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]); +// pclog("ASP read reg %02X %02X\n", sb_data[0], sb_asp_regs[sb_data[0]]); + break; + case 0xF9: + if (dsp->sb_type < SB16) break; + if (dsp->sb_data[0] == 0x0e) sb_add_data(dsp, 0xff); + else if (dsp->sb_data[0] == 0x0f) sb_add_data(dsp, 0x07); + else if (dsp->sb_data[0] == 0x37) sb_add_data(dsp, 0x38); + else sb_add_data(dsp, 0x00); + case 0x04: + case 0x05: + break; +// default: +// fatal("Exec bad SB command %02X\n",sb_command); + } +} + +void sb_write(uint16_t a, uint8_t v, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *)priv; +// pclog("sb_write : Write soundblaster %04X %02X %04X:%04X %02X\n",a,v,CS,pc,dsp->sb_command); + switch (a&0xF) + { + case 6: /*Reset*/ + if (!(v & 1) && (dsp->sbreset & 1)) + { + sb_dsp_reset(dsp); + sb_add_data(dsp, 0xAA); + } + dsp->sbreset = v; + return; + case 0xC: /*Command/data write*/ + timer_process(); + dsp->wb_time = TIMER_USEC * 1; + dsp->wb_full = 1; + timer_update_outstanding(); + if (dsp->asp_data_len) + { +// pclog("ASP data %i\n", dsp->asp_data_len); + dsp->asp_data_len--; + if (!dsp->asp_data_len) + sb_add_data(dsp, 0); + return; + } + if (dsp->sb_data_stat == -1) + { + dsp->sb_command = v; + if (v == 0x01) + sb_add_data(dsp, 0); +// if (sb_commands[v]==-1) +// fatal("Bad SB command %02X\n",v); + dsp->sb_data_stat++; + } + else + dsp->sb_data[dsp->sb_data_stat++] = v; + if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) + { + sb_exec_command(dsp); + dsp->sb_data_stat = -1; + } + break; + } +} + +uint8_t sb_read(uint16_t a, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *)priv; +// if (a==0x224) output=1; +// pclog("sb_read : Read soundblaster %04X %04X:%04X\n",a,CS,pc); + switch (a & 0xf) + { + case 0xA: /*Read data*/ + dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; + if (dsp->sb_read_rp != dsp->sb_read_wp) + { + dsp->sb_read_rp++; + dsp->sb_read_rp &= 0xFF; + } +// pclog("SB read %02X\n",sbreaddat); + return dsp->sbreaddat; + case 0xC: /*Write data ready*/ + if (dsp->wb_full) + { + dsp->wb_full = dsp->wb_time; + return 0xff; + } + return 0x7f; + case 0xE: /*Read data ready*/ + picintc(1 << dsp->sb_irqnum); + dsp->sb_irq8 = dsp->sb_irq16 = 0; + return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; + case 0xF: /*16-bit ack*/ + dsp->sb_irq16 = 0; + if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum); + return 0xff; + } + return 0; +} + +static void sb_wb_clear(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + + dsp->wb_time = 0; +} + +void sb_dsp_init(sb_dsp_t *dsp, int type) +{ + dsp->sb_type = type; + + dsp->sb_irqnum = 7; + dsp->sb_8_dmanum = 1; + + sb_doreset(dsp); + + timer_add(pollsb, &dsp->sbcount, &dsp->sbenable, dsp); + timer_add(sb_poll_i, &dsp->sb_count_i, &dsp->sb_enable_i, dsp); + timer_add(sb_wb_clear, &dsp->wb_time, &dsp->wb_time, dsp); +} + +void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) +{ +// pclog("sb_dsp_setaddr : %04X\n", addr); + io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + dsp->sb_addr = addr; + if (dsp->sb_addr != 0) + { + io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + } +} + +void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo) +{ + dsp->stereo = stereo; +} + +void pollsb(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + int tempi,ref; + + dsp->sbcount += dsp->sblatcho; +// pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); + if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) + { + int data[2]; + + sb_dsp_update(dsp); +// pclog("Dopoll %i %02X %i\n", sb_8_length, sb_8_format, sblatcho); + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned*/ + data[0] = sb_8_read_dma(dsp); + /*Needed to prevent clicking in Worms, which programs the DSP to + auto-init DMA but programs the DMA controller to single cycle*/ + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = (data[0] ^ 0x80) << 8; + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x10: /*Mono signed*/ + data[0] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = data[0] << 8; + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x20: /*Stereo unsigned*/ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = (data[0] ^ 0x80) << 8; + dsp->sbdatr = (data[1] ^ 0x80) << 8; + dsp->sb_8_length -= 2; + break; + case 0x30: /*Stereo signed*/ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0] << 8; + dsp->sbdatr = data[1] << 8; + dsp->sb_8_length -= 2; + break; + + case ADPCM_4: + if (dsp->sbdacpos) tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep; + else tempi = (dsp->sbdat2 >> 4) + dsp->sbstep; + if (tempi < 0) tempi = 0; + if (tempi > 63) tempi = 63; + + ref = dsp->sbref + scaleMap4[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + + dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 2) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_26: + if (!dsp->sbdacpos) tempi = (dsp->sbdat2 >> 5) + dsp->sbstep; + else if (dsp->sbdacpos == 1) tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep; + else tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep; + + if (tempi < 0) tempi = 0; + if (tempi > 39) tempi = 39; + + ref = dsp->sbref + scaleMap26[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos>=3) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_2: + tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep; + if (tempi < 0) tempi = 0; + if (tempi > 23) tempi = 23; + + ref = dsp->sbref + scaleMap2[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 4) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + +// default: + //fatal("Unrecognised SB 8-bit format %02X\n",sb_8_format); + } + + if (dsp->sb_8_length < 0) + { + if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; + else dsp->sb_8_enable = dsp->sbenable=0; + sb_irq(dsp, 1); + } + } + if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && dsp->sb_16_output) + { + sb_dsp_update(dsp); + + switch (dsp->sb_16_format) + { + case 0x00: /*Mono unsigned*/ + dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000; + dsp->sb_16_length--; + break; + case 0x10: /*Mono signed*/ + dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp); + dsp->sb_16_length--; + break; + case 0x20: /*Stereo unsigned*/ + dsp->sbdatl = sb_16_read_dma(dsp) ^ 0x8000; + dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000; + dsp->sb_16_length -= 2; + break; + case 0x30: /*Stereo signed*/ + dsp->sbdatl = sb_16_read_dma(dsp); + dsp->sbdatr = sb_16_read_dma(dsp); + dsp->sb_16_length -= 2; + break; + +// default: +// fatal("Unrecognised SB 16-bit format %02X\n",sb_16_format); + } + + if (dsp->sb_16_length < 0) + { +// pclog("16DMA over %i\n",dsp->sb_16_autoinit); + if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; + else dsp->sb_16_enable = dsp->sbenable = 0; + sb_irq(dsp, 0); + } + } + if (dsp->sb_pausetime > -1) + { + dsp->sb_pausetime--; + if (dsp->sb_pausetime < 0) + { + sb_irq(dsp, 1); + dsp->sbenable = dsp->sb_8_enable; +// pclog("SB pause over\n"); + } + } +} + +void sb_poll_i(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + + dsp->sb_count_i += dsp->sblatchi; +// pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); + if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output) + { + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned*/ + sb_8_write_dma(dsp, 0x80); + dsp->sb_8_length--; + break; + case 0x10: /*Mono signed*/ + sb_8_write_dma(dsp, 0x00); + dsp->sb_8_length--; + break; + case 0x20: /*Stereo unsigned*/ + sb_8_write_dma(dsp, 0x80); + sb_8_write_dma(dsp, 0x80); + dsp->sb_8_length -= 2; + break; + case 0x30: /*Stereo signed*/ + sb_8_write_dma(dsp, 0x00); + sb_8_write_dma(dsp, 0x00); + dsp->sb_8_length -= 2; + break; + +// default: +// fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format); + } + + if (dsp->sb_8_length < 0) + { +// pclog("Input DMA over %i\n",sb_8_autoinit); + if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; + else dsp->sb_8_enable = dsp->sbenable = 0; + sb_irq(dsp, 1); + } + } + if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && !dsp->sb_16_output) + { + switch (dsp->sb_16_format) + { + case 0x00: /*Unsigned mono*/ + sb_16_write_dma(dsp, 0x8000); + dsp->sb_16_length--; + break; + case 0x10: /*Signed mono*/ + sb_16_write_dma(dsp, 0); + dsp->sb_16_length--; + break; + case 0x20: /*Unsigned stereo*/ + sb_16_write_dma(dsp, 0x8000); + sb_16_write_dma(dsp, 0x8000); + dsp->sb_16_length -= 2; + break; + case 0x30: /*Signed stereo*/ + sb_16_write_dma(dsp, 0); + sb_16_write_dma(dsp, 0); + dsp->sb_16_length -= 2; + break; + +// default: +// fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format); + } + + if (dsp->sb_16_length < 0) + { +// pclog("16iDMA over %i\n",sb_16_autoinit); + if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; + else dsp->sb_16_enable = dsp->sbenable = 0; + sb_irq(dsp, 0); + } + } +} + +void sb_dsp_update(sb_dsp_t *dsp) +{ + for (; dsp->pos < sound_pos_global; dsp->pos++) + { + dsp->buffer[dsp->pos*2] = dsp->sbdatl; + dsp->buffer[dsp->pos*2 + 1] = dsp->sbdatr; + } +} + +void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp) +{ + char temps[128]; + int len; + int freq; + + if (dsp->sb_timeo < 256) + freq = 1000000 / (256 - dsp->sb_timeo); + else + freq = dsp->sb_timeo - 256; + + if (dsp->sb_8_enable && dsp->sb_8_output) + { + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned*/ + case 0x10: /*Mono signed*/ + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + strcpy(temps, "SB playback format : 8-bit stereo\n"); + freq /= 2; + } + else + strcpy(temps, "SB playback format : 8-bit mono\n"); + break; + case 0x20: /*Stereo unsigned*/ + case 0x30: /*Stereo signed*/ + strcpy(temps, "SB playback format : 8-bit stereo\n"); + break; + case ADPCM_4: + strcpy(temps, "SB playback format : 4-bit ADPCM\n"); + break; + case ADPCM_26: + strcpy(temps, "SB playback format : 2.6-bit ADPCM\n"); + break; + case ADPCM_2: + strcpy(temps, "SB playback format : 2-bit ADPCM\n"); + break; + } + } + else if (dsp->sb_16_enable && dsp->sb_16_output) + { + switch (dsp->sb_16_format) + { + case 0x00: /*Mono unsigned*/ + case 0x10: /*Mono signed*/ + strcpy(temps, "SB playback format : 16-bit mono\n"); + break; + case 0x20: /*Stereo unsigned*/ + case 0x30: /*Stereo signed*/ + strcpy(temps, "SB playback format : 16-bit stereo\n"); + break; + } + } + else + strcpy(temps, "SB playback stopped\n"); + strncat(s, temps, max_len); + + if ((dsp->sb_8_enable && dsp->sb_8_output) || (dsp->sb_16_enable && dsp->sb_16_output)) + { + sprintf(temps, "SB playback frequency : %iHz\n", freq); + strncat(s, temps, max_len); + } +} diff --git a/src/sound_sb_dsp.h b/src/sound_sb_dsp.h new file mode 100644 index 000000000..444513642 --- /dev/null +++ b/src/sound_sb_dsp.h @@ -0,0 +1,78 @@ +typedef struct sb_dsp_t +{ + int sb_type; + + int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; + int sb_8_dmanum; + int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; + int sb_pausetime; + + uint8_t sb_read_data[256]; + int sb_read_wp, sb_read_rp; + int sb_speaker; + + int sb_data_stat; + + int sb_irqnum; + + uint8_t sbe2; + int sbe2count; + + uint8_t sb_data[8]; + + int sb_freq; + + int16_t sbdat; + int sbdat2; + int16_t sbdatl, sbdatr; + + uint8_t sbref; + int8_t sbstep; + + int sbdacpos; + + int sbleftright; + + int sbreset; + uint8_t sbreaddat; + uint8_t sb_command; + uint8_t sb_test; + int sb_timei, sb_timeo; + + int sb_irq8, sb_irq16; + + uint8_t sb_asp_regs[256]; + + int sbenable, sb_enable_i; + + int sbcount, sb_count_i; + + int sblatcho, sblatchi; + + uint16_t sb_addr; + + int stereo; + + int asp_data_len; + + int wb_time, wb_full; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} sb_dsp_t; + +void sb_dsp_init(sb_dsp_t *dsp, int type); + +void sb_dsp_setirq(sb_dsp_t *dsp, int irq); +void sb_dsp_setdma8(sb_dsp_t *dsp, int dma); +void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr); + +void sb_dsp_speed_changed(sb_dsp_t *dsp); + +void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r); + +void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo); + +void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp); + +void sb_dsp_update(sb_dsp_t *dsp); diff --git a/src/sound_sn76489.c b/src/sound_sn76489.c new file mode 100644 index 000000000..2dae07669 --- /dev/null +++ b/src/sound_sn76489.c @@ -0,0 +1,250 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_sn76489.h" + +int sn76489_mute; + +static float volslog[16]= +{ + 0.00000f,0.59715f,0.75180f,0.94650f, + 1.19145f,1.50000f,1.88835f,2.37735f, + 2.99295f,3.76785f,4.74345f,5.97165f, + 7.51785f,9.46440f,11.9194f,15.0000f +}; + +//#define PSGCONST ((3579545.0 / 64.0) / 48000.0) + +void sn76489_update(sn76489_t *sn76489) +{ + for (; sn76489->pos < sound_pos_global; sn76489->pos++) + { + int c; + int16_t result = 0; + + for (c = 1; c < 4; c++) + { + if (sn76489->latch[c] > 256) result += (int16_t) (volslog[sn76489->vol[c]] * sn76489->stat[c]); + else result += (int16_t) (volslog[sn76489->vol[c]] * 127); + + sn76489->count[c] -= (256 * sn76489->psgconst); + while ((int)sn76489->count[c] < 0) + { + sn76489->count[c] += sn76489->latch[c]; + sn76489->stat[c] = -sn76489->stat[c]; + } + } + result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2); + + sn76489->count[0] -= (512 * sn76489->psgconst); + while ((int)sn76489->count[0] < 0 && sn76489->latch[0]) + { + sn76489->count[0] += (sn76489->latch[0] * 4); + if (!(sn76489->noise & 4)) + { + if (sn76489->shift & 1) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } + else + { + if ((sn76489->shift & 1) ^ ((sn76489->shift >> 1) & 1)) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } + } + + sn76489->buffer[sn76489->pos] = result; + } +} + +void sn76489_get_buffer(int32_t *buffer, int len, void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + + int c; + + sn76489_update(sn76489); + + if (!sn76489_mute) + { + for (c = 0; c < len * 2; c++) + buffer[c] += sn76489->buffer[c >> 1]; + } + + sn76489->pos = 0; +} + +void sn76489_write(uint16_t addr, uint8_t data, void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + int freq; + + sn76489_update(sn76489); + + if (data & 0x80) + { + sn76489->firstdat = data; + switch (data & 0x70) + { + case 0: + sn76489->freqlo[3] = data & 0xf; + sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[3] &= 0x3ff; + if (!sn76489->latch[3]) + sn76489->latch[3] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 3; + break; + case 0x10: + data &= 0xf; + sn76489->vol[3] = 0xf - data; + break; + case 0x20: + sn76489->freqlo[2] = data & 0xf; + sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[2] &= 0x3ff; + if (!sn76489->latch[2]) + sn76489->latch[2] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 2; + break; + case 0x30: + data &= 0xf; + sn76489->vol[2] = 0xf - data; + break; + case 0x40: + sn76489->freqlo[1] = data & 0xf; + sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[1] &= 0x3ff; + if (!sn76489->latch[1]) + sn76489->latch[1] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 1; + break; + case 0x50: + data &= 0xf; + sn76489->vol[1] = 0xf - data; + break; + case 0x60: + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) + sn76489->shift = 0x4000; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; + else sn76489->latch[0] = 0x400 << (data & 3); + if (sn76489->extra_divide) + sn76489->latch[0] &= 0x3ff; + if (!sn76489->latch[0]) + sn76489->latch[0] = (sn76489->extra_divide ? 2048 : 1024) << 6; + break; + case 0x70: + data &= 0xf; + sn76489->vol[0] = 0xf - data; + break; + } + } + else + { + if ((sn76489->firstdat & 0x70) == 0x60 && (sn76489->type == SN76496)) + { + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) + sn76489->shift = 0x4000; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; + else sn76489->latch[0] = 0x400 << (data & 3); + if (!sn76489->latch[0]) + sn76489->latch[0] = 1024 << 6; + } + else if ((sn76489->firstdat & 0x70) != 0x60) + { + sn76489->freqhi[sn76489->lasttone] = data & 0x7F; + freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4); + if (sn76489->extra_divide) + freq &= 0x3ff; + if (!freq) + freq = sn76489->extra_divide ? 2048 : 1024; + if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1) + sn76489->latch[0] = freq << 6; + sn76489->latch[sn76489->lasttone] = freq << 6; + } + } +} + +void sn74689_set_extra_divide(sn76489_t *sn76489, int enable) +{ + sn76489->extra_divide = enable; +} + +void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq) +{ + sound_add_handler(sn76489_get_buffer, sn76489); + + sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6; + sn76489->vol[0] = 0; + sn76489->vol[1] = sn76489->vol[2] = sn76489->vol[3] = 8; + sn76489->stat[0] = sn76489->stat[1] = sn76489->stat[2] = sn76489->stat[3] = 127; + srand(time(NULL)); + sn76489->count[0] = 0; + sn76489->count[1] = (rand()&0x3FF)<<6; + sn76489->count[2] = (rand()&0x3FF)<<6; + sn76489->count[3] = (rand()&0x3FF)<<6; + sn76489->noise = 3; + sn76489->shift = 0x4000; + sn76489->type = type; + sn76489->psgconst = (((double)freq / 64.0) / 48000.0); + + sn76489_mute = 0; + + io_sethandler(base, size, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489); +} + +void *sn76489_device_init() +{ + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); + + sn76489_init(sn76489, 0x00c0, 0x0008, SN76496, 3579545); + + return sn76489; +} +void *ncr8496_device_init() +{ + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); + + sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496, 3579545); + + return sn76489; +} + +void sn76489_device_close(void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + + free(sn76489); +} + +device_t sn76489_device = +{ + "TI SN74689 PSG", + 0, + sn76489_device_init, + sn76489_device_close, + NULL, + NULL, + NULL, + NULL +}; +device_t ncr8496_device = +{ + "NCR8496 PSG", + 0, + ncr8496_device_init, + sn76489_device_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_sn76489.h b/src/sound_sn76489.h new file mode 100644 index 000000000..84c102821 --- /dev/null +++ b/src/sound_sn76489.h @@ -0,0 +1,33 @@ +enum +{ + SN76496, + NCR8496, + PSSJ +}; + +extern device_t sn76489_device; +extern device_t ncr8496_device; + +extern int sn76489_mute; + +typedef struct sn76489_t +{ + int stat[4]; + int latch[4], count[4]; + int freqlo[4], freqhi[4]; + int vol[4]; + uint32_t shift; + uint8_t noise; + int lasttone; + uint8_t firstdat; + int type; + int extra_divide; + + int16_t buffer[SOUNDBUFLEN]; + int pos; + + double psgconst; +} sn76489_t; + +void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq); +void sn74689_set_extra_divide(sn76489_t *sn76489, int enable); diff --git a/src/sound_speaker.c b/src/sound_speaker.c new file mode 100644 index 000000000..8e678253e --- /dev/null +++ b/src/sound_speaker.c @@ -0,0 +1,59 @@ +#include "ibm.h" +#include "sound.h" +#include "sound_speaker.h" + +int speaker_mute = 0; + +static int16_t speaker_buffer[SOUNDBUFLEN]; + +static int speaker_pos = 0; + +int speaker_gated = 0; +int speaker_enable = 0, was_speaker_enable = 0; + +void speaker_update() +{ + int16_t val; + +// printf("SPeaker - %i %i %i %02X\n",speakval,gated,speakon,pit.m[2]); + for (; speaker_pos < sound_pos_global; speaker_pos++) + { + if (speaker_gated && was_speaker_enable) + { + if (!pit.m[2] || pit.m[2]==4) + val = speakval; + else if (pit.l[2] < 0x40) + val = 0xa00; + else + val = speakon ? 0x1400 : 0; + } + else + val = was_speaker_enable ? 0x1400 : 0; + + if (!speaker_enable) + was_speaker_enable = 0; + + speaker_buffer[speaker_pos] = val; + } +} + +static void speaker_get_buffer(int32_t *buffer, int len, void *p) +{ + int c; + + speaker_update(); + + if (!speaker_mute) + { + for (c = 0; c < len * 2; c++) + buffer[c] += speaker_buffer[c >> 1]; + } + + speaker_pos = 0; +} + +void speaker_init() +{ + sound_add_handler(speaker_get_buffer, NULL); + speaker_mute = 0; +} diff --git a/src/sound_speaker.h b/src/sound_speaker.h new file mode 100644 index 000000000..409a7c4e6 --- /dev/null +++ b/src/sound_speaker.h @@ -0,0 +1,8 @@ +void speaker_init(); + +extern int speaker_mute; + +extern int speaker_gated; +extern int speaker_enable, was_speaker_enable; + +void speaker_update(); diff --git a/src/sound_ssi2001.c b/src/sound_ssi2001.c new file mode 100644 index 000000000..fd675c309 --- /dev/null +++ b/src/sound_ssi2001.c @@ -0,0 +1,87 @@ +#include +#include "ibm.h" +#include "device.h" +#include "sound.h" + +#include "sound_resid.h" +#include "sound_ssi2001.h" + +typedef struct ssi2001_t +{ + void *psid; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} ssi2001_t; + +static void ssi2001_update(ssi2001_t *ssi2001) +{ + if (ssi2001->pos >= sound_pos_global) + return; + + sid_fillbuf(&ssi2001->buffer[ssi2001->pos], sound_pos_global - ssi2001->pos, ssi2001->psid); + ssi2001->pos = sound_pos_global; +} + +static void ssi2001_get_buffer(int32_t *buffer, int len, void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + int c; + + ssi2001_update(ssi2001); + + for (c = 0; c < len * 2; c++) + buffer[c] += ssi2001->buffer[c >> 1] / 2; + + ssi2001->pos = 0; +} + +static uint8_t ssi2001_read(uint16_t addr, void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + + ssi2001_update(ssi2001); + + return sid_read(addr, p); +} + +static void ssi2001_write(uint16_t addr, uint8_t val, void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + + ssi2001_update(ssi2001); + sid_write(addr, val, p); +} + +void *ssi2001_init() +{ + ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t)); + memset(ssi2001, 0, sizeof(ssi2001_t)); + + pclog("ssi2001_init\n"); + ssi2001->psid = sid_init(); + sid_reset(ssi2001->psid); + io_sethandler(0x0280, 0x0020, ssi2001_read, NULL, NULL, ssi2001_write, NULL, NULL, ssi2001); + sound_add_handler(ssi2001_get_buffer, ssi2001); + return ssi2001; +} + +void ssi2001_close(void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + + sid_close(ssi2001->psid); + + free(ssi2001); +} + +device_t ssi2001_device = +{ + "Innovation SSI-2001", + 0, + ssi2001_init, + ssi2001_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_ssi2001.h b/src/sound_ssi2001.h new file mode 100644 index 000000000..337c6260a --- /dev/null +++ b/src/sound_ssi2001.h @@ -0,0 +1 @@ +extern device_t ssi2001_device; diff --git a/src/sound_wss.c b/src/sound_wss.c new file mode 100644 index 000000000..b5fecd08f --- /dev/null +++ b/src/sound_wss.c @@ -0,0 +1,125 @@ +/*PCem v0.8 by Tom Walker + + Windows Sound System emulation*/ + +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "sound_ad1848.h" +#include "sound_opl.h" +#include "sound_wss.h" + +/*530, 11, 3 - 530=23*/ +/*530, 11, 1 - 530=22*/ +/*530, 11, 0 - 530=21*/ +/*530, 10, 1 - 530=1a*/ +/*530, 9, 1 - 530=12*/ +/*530, 7, 1 - 530=0a*/ +/*604, 11, 1 - 530=22*/ +/*e80, 11, 1 - 530=22*/ +/*f40, 11, 1 - 530=22*/ + + +static int wss_dma[4] = {0, 0, 1, 3}; +static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ +static uint16_t wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; + +typedef struct wss_t +{ + uint8_t config; + + ad1848_t ad1848; + opl_t opl; +} wss_t; + +uint8_t wss_read(uint16_t addr, void *p) +{ + wss_t *wss = (wss_t *)p; + uint8_t temp; +// pclog("wss_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); + temp = 4 | (wss->config & 0x40); +// pclog("return %02X\n", temp); + return temp; +} + +void wss_write(uint16_t addr, uint8_t val, void *p) +{ + wss_t *wss = (wss_t *)p; +// pclog("wss_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); + + wss->config = val; + ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); + ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); +} + +static void wss_get_buffer(int32_t *buffer, int len, void *p) +{ + wss_t *wss = (wss_t *)p; + + int c; + + opl3_update2(&wss->opl); + ad1848_update(&wss->ad1848); + for (c = 0; c < len * 2; c++) + { + buffer[c] += wss->opl.buffer[c]; + buffer[c] += (wss->ad1848.buffer[c] / 2); + } + + wss->opl.pos = 0; + wss->ad1848.pos = 0; +} + +void *wss_init() +{ + wss_t *wss = malloc(sizeof(wss_t)); + int c; + double attenuation; + + memset(wss, 0, sizeof(wss_t)); + + opl3_init(&wss->opl); + ad1848_init(&wss->ad1848); + + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); + + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + io_sethandler(0x0530, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(0x0534, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + sound_add_handler(wss_get_buffer, wss); + + return wss; +} + +void wss_close(void *p) +{ + wss_t *wss = (wss_t *)p; + + free(wss); +} + +void wss_speed_changed(void *p) +{ + wss_t *wss = (wss_t *)p; + + ad1848_speed_changed(&wss->ad1848); +} + +device_t wss_device = +{ + "Windows Sound System", + 0, + wss_init, + wss_close, + NULL, + wss_speed_changed, + NULL, + NULL +}; diff --git a/src/sound_wss.h b/src/sound_wss.h new file mode 100644 index 000000000..bd387d6f3 --- /dev/null +++ b/src/sound_wss.h @@ -0,0 +1 @@ +extern device_t wss_device; diff --git a/src/sound_ym7128.c b/src/sound_ym7128.c new file mode 100644 index 000000000..7c1aa06ff --- /dev/null +++ b/src/sound_ym7128.c @@ -0,0 +1,142 @@ +#include "ibm.h" +#include "sound_ym7128.h" + +static int attenuation[32]; +static int tap_position[32]; + +void ym7128_init(ym7128_t *ym7128) +{ + int c; + double out = 65536.0; + + for (c = 0; c < 32; c++) + tap_position[c] = c * (2400 / 31); + + for (c = 31; c >= 1; c--) + { + attenuation[c] = (int)out; + out /= 1.25963; /*2 dB steps*/ + } + attenuation[0] = 0; +} + +#define GET_ATTENUATION(val) (val & 0x20) ? -attenuation[val & 0x1f] : attenuation[val & 0x1f] + +void ym7128_write(ym7128_t *ym7128, uint8_t val) +{ + int new_dat = val & 1; + int new_sci = val & 2; + int new_a0 = val & 4; +// pclog("ym7128_write %i %i %i\n", new_dat, new_sci, new_a0); + if (!ym7128->sci && new_sci) + ym7128->dat = (ym7128->dat << 1) | new_dat; + + if (ym7128->a0 != new_a0) + { +// pclog("ym7128 write %i %02x\n", ym7128->a0, ym7128->dat); + if (!ym7128->a0) + ym7128->reg_sel = ym7128->dat & 0x1f; + else + { +// pclog("YM7128 write %02x %02x\n", ym7128->reg_sel, ym7128->dat); + switch (ym7128->reg_sel) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + ym7128->gl[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); +// pclog(" GL[%i] = %04x\n", ym7128->reg_sel & 7, GET_ATTENUATION(ym7128->dat)); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + ym7128->gr[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); +// pclog(" GR[%i] = %04x\n", ym7128->reg_sel & 7, GET_ATTENUATION(ym7128->dat)); + break; + + case 0x10: + ym7128->vm = GET_ATTENUATION(ym7128->dat); +// pclog(" VM = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + case 0x11: + ym7128->vc = GET_ATTENUATION(ym7128->dat); +// pclog(" VC = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + case 0x12: + ym7128->vl = GET_ATTENUATION(ym7128->dat); +// pclog(" VL = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + case 0x13: + ym7128->vr = GET_ATTENUATION(ym7128->dat); +// pclog(" VR = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + + case 0x14: + ym7128->c0 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c0 |= 0xfffff000; + break; + case 0x15: + ym7128->c1 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c1 |= 0xfffff000; + break; + + case 0x16: case 0x17: case 0x18: case 0x19: + case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: + ym7128->t[ym7128->reg_sel - 0x16] = tap_position[ym7128->dat & 0x1f]; +// pclog(" T[%i] = %i\n", ym7128->reg_sel - 0x16, tap_position[ym7128->dat & 0x1f]); + break; + } + ym7128->regs[ym7128->reg_sel] = ym7128->dat; + } + ym7128->dat = 0; + } + + ym7128->sci = new_sci; + ym7128->a0 = new_a0; +} + +#define GET_DELAY_SAMPLE(ym7128, offset) (((ym7128->delay_pos - offset) < 0) ? ym7128->delay_buffer[(ym7128->delay_pos - offset) + 2400] : ym7128->delay_buffer[ym7128->delay_pos - offset]) + +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) +{ + int c, d; + + for (c = 0; c < len*2; c += 4) + { + /*YM7128 samples a mono stream at ~24 kHz, so downsample*/ + int32_t samp = ((int32_t)buffer[c] + (int32_t)buffer[c+1] + (int32_t)buffer[c+2] + (int32_t)buffer[c+3]) / 4; + int32_t filter_temp, filter_out; + int32_t samp_l = 0, samp_r = 0; + + filter_temp = GET_DELAY_SAMPLE(ym7128, ym7128->t[0]); + filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat * ym7128->c1) >> 11); + filter_out = (filter_out * ym7128->vc) >> 16; + + samp = (samp * ym7128->vm) >> 16; + samp += filter_out; + + ym7128->delay_buffer[ym7128->delay_pos] = samp; + + for (d = 0; d < 8; d++) + { + samp_l += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gl[d]) >> 16; + samp_r += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gr[d]) >> 16; + } + + samp_l = (samp_l * ym7128->vl*2) >> 16; + samp_r = (samp_r * ym7128->vr*2) >> 16; + + buffer[c] += ((int32_t)samp_l + (int32_t)ym7128->prev_l) / 2; + buffer[c+1] += ((int32_t)samp_r + (int32_t)ym7128->prev_r) / 2; + buffer[c+2] += samp_l; + buffer[c+3] += samp_r; + + ym7128->delay_pos++; + if (ym7128->delay_pos >= 2400) + ym7128->delay_pos = 0; + + ym7128->filter_dat = filter_temp; + ym7128->prev_l = samp_l; + ym7128->prev_r = samp_r; + } +} diff --git a/src/sound_ym7128.h b/src/sound_ym7128.h new file mode 100644 index 000000000..f71aa2f86 --- /dev/null +++ b/src/sound_ym7128.h @@ -0,0 +1,25 @@ +typedef struct ym7128_t +{ + int a0, sci; + uint8_t dat; + + int reg_sel; + uint8_t regs[32]; + + int gl[8], gr[8]; + int vm, vc, vl, vr; + int c0, c1; + int t[9]; + + int16_t filter_dat; + int16_t prev_l, prev_r; + + int16_t delay_buffer[2400]; + int delay_pos; + + int16_t last_samp; +} ym7128_t; + +void ym7128_init(ym7128_t *ym7128); +void ym7128_write(ym7128_t *ym7128, uint8_t val); +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len); diff --git a/src/soundopenal.c b/src/soundopenal.c new file mode 100644 index 000000000..78f81ed87 --- /dev/null +++ b/src/soundopenal.c @@ -0,0 +1,257 @@ +#define USE_OPENAL +#include +#include +#include +#ifdef USE_OPENAL +#include +#include +#endif +#include "ibm.h" +#include "sound.h" + +FILE *allog; +#ifdef USE_OPENAL +ALuint buffers[4]; // front and back buffers +ALuint buffers_cd[4]; // front and back buffers +static ALuint source[2]; // audio source +#endif +#define FREQ 48000 +#define BUFLEN SOUNDBUFLEN + +void closeal(); +ALvoid alutInit(ALint *argc,ALbyte **argv) +{ + ALCcontext *Context; + ALCdevice *Device; + + //Open device + Device=alcOpenDevice((ALubyte*)""); + //Create context(s) + Context=alcCreateContext(Device,NULL); + //Set active context + alcMakeContextCurrent(Context); + //Register extensions +} + +ALvoid alutExit(ALvoid) +{ + ALCcontext *Context; + ALCdevice *Device; + + //Unregister extensions + + //Get active context + Context=alcGetCurrentContext(); + //Get device for active context + Device=alcGetContextsDevice(Context); + //Disable context + alcMakeContextCurrent(NULL); + //Release context(s) + alcDestroyContext(Context); + //Close device + alcCloseDevice(Device); +} +void initalmain(int argc, char *argv[]) +{ +#ifdef USE_OPENAL + alutInit(0,0); +// printf("AlutInit\n"); + atexit(closeal); +// printf("AlutInit\n"); +#endif +} + +void closeal() +{ +#ifdef USE_OPENAL + alutExit(); +#endif +} + +void check() +{ +#ifdef USE_OPENAL + ALenum error; + if ((error = alGetError()) != AL_NO_ERROR) + { +// printf("Error : %08X\n", error); +// exit(-1); + } +#endif +} + +void inital() +{ +#ifdef USE_OPENAL + int c; + int16_t buf[BUFLEN*2]; + +// printf("1\n"); + check(); + +// printf("2\n"); + alGenBuffers(4, buffers); + check(); + alGenBuffers(4, buffers_cd); + check(); + +// printf("3\n"); + alGenSources(2, source); + check(); + +// printf("4\n"); + alSource3f(source[0], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[0], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[0], AL_SOURCE_RELATIVE, AL_TRUE ); + check(); + alSource3f(source[1], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[1], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[1], AL_SOURCE_RELATIVE, AL_TRUE ); + check(); + + memset(buf,0,BUFLEN*4); + +// printf("5\n"); + for (c = 0; c < 4; c++) + { + alBufferData(buffers[c], AL_FORMAT_STEREO16, buf, BUFLEN*2*2, FREQ); + alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, buf, CD_BUFLEN*2*2, CD_FREQ); + } + + alSourceQueueBuffers(source[0], 4, buffers); + check(); + alSourceQueueBuffers(source[1], 4, buffers_cd); + check(); +// printf("6 %08X\n",source); + alSourcePlay(source[0]); + check(); + alSourcePlay(source[1]); + check(); +// printf("InitAL!!! %08X\n",source); +#endif +} + +void givealbuffer(int32_t *buf) +{ +#ifdef USE_OPENAL + int16_t buf16[BUFLEN*2]; + int processed; + int state; + + //return; + +// printf("Start\n"); + check(); + +// printf("GiveALBuffer %08X\n",source); + + alGetSourcei(source[0], AL_SOURCE_STATE, &state); + + check(); + + if (state==0x1014) + { + alSourcePlay(source[0]); +// printf("Resetting sound\n"); + } +// printf("State - %i %08X\n",state,state); + alGetSourcei(source[0], AL_BUFFERS_PROCESSED, &processed); + +// printf("P "); + check(); +// printf("Processed - %i\n",processed); + + if (processed>=1) + { + int c; + ALuint buffer; + + alSourceUnqueueBuffers(source[0], 1, &buffer); +// printf("U "); + check(); + + for (c=0;c 32767) + buf16[c] = 32767; + else + buf16[c] = buf[c]; + } +// for (c=0;c=1) + { + ALuint buffer; + + alSourceUnqueueBuffers(source[1], 1, &buffer); +// printf("U "); + check(); + +// for (c=0;c +#include "ibm.h" +#include "device.h" +#include "tandy_eeprom.h" + +typedef struct +{ + int state; + int count; + int addr; + int clock; + uint16_t data; + uint16_t store[64]; + + int romset; +} tandy_eeprom_t; + +enum +{ + EEPROM_IDLE, + EEPROM_GET_OPERATION, + EEPROM_READ, + EEPROM_WRITE +}; + +static int eeprom_data_out; + +void tandy_eeprom_write(uint16_t addr, uint8_t val, void *p) +{ + tandy_eeprom_t *eeprom = (tandy_eeprom_t *)p; + + if ((val & 4) && !eeprom->clock) + { +// pclog("eeprom_write %02x %i %i\n", val, eeprom->state, eeprom->count); + switch (eeprom->state) + { + case EEPROM_IDLE: + switch (eeprom->count) + { + case 0: + if (!(val & 3)) + eeprom->count = 1; + else + eeprom->count = 0; + break; + case 1: + if ((val & 3) == 2) + eeprom->count = 2; + else + eeprom->count = 0; + break; + case 2: + if ((val & 3) == 3) + eeprom->state = EEPROM_GET_OPERATION; + eeprom->count = 0; + break; + } + break; + case EEPROM_GET_OPERATION: + eeprom->data = (eeprom->data << 1) | (val & 1); + eeprom->count++; + if (eeprom->count == 8) + { + eeprom->count = 0; +// pclog("EEPROM get operation %02x\n", eeprom->data); + eeprom->addr = eeprom->data & 0x3f; + switch (eeprom->data & 0xc0) + { + case 0x40: + eeprom->state = EEPROM_WRITE; + break; + case 0x80: + eeprom->state = EEPROM_READ; + eeprom->data = eeprom->store[eeprom->addr]; +// pclog("EEPROM read data %02x %04x\n", eeprom->addr, eeprom->data); + break; + default: + eeprom->state = EEPROM_IDLE; + break; + } + } + break; + + case EEPROM_READ: + eeprom_data_out = eeprom->data & 0x8000; + eeprom->data <<= 1; + eeprom->count++; + if (eeprom->count == 16) + { + eeprom->count = 0; + eeprom->state = EEPROM_IDLE; + } + break; + case EEPROM_WRITE: + eeprom->data = (eeprom->data << 1) | (val & 1); + eeprom->count++; + if (eeprom->count == 16) + { + eeprom->count = 0; + eeprom->state = EEPROM_IDLE; +// pclog("EEPROM write %04x to %02x\n", eeprom->data, eeprom->addr); + eeprom->store[eeprom->addr] = eeprom->data; + } + break; + } + } + + eeprom->clock = val & 4; +} + +int tandy_eeprom_read() +{ +// pclog("tandy_eeprom_read: data_out=%x\n", eeprom_data_out); + return eeprom_data_out; +} + +void *tandy_eeprom_init() +{ + tandy_eeprom_t *eeprom = malloc(sizeof(tandy_eeprom_t)); + FILE *f; + + memset(eeprom, 0, sizeof(tandy_eeprom_t)); + + eeprom->romset = romset; + switch (romset) + { + case ROM_TANDY1000HX: + f = romfopen("nvr/tandy1000hx.bin" ,"rb"); + break; + case ROM_TANDY1000SL2: + f = romfopen("nvr/tandy1000sl2.bin" ,"rb"); + break; + } + if (f) + { + fread(eeprom->store, 128, 1, f); + fclose(f); + } + else + memset(eeprom->store, 0, 128); + + io_sethandler(0x037c, 0x0001, NULL, NULL, NULL, tandy_eeprom_write, NULL, NULL, eeprom); + + return eeprom; +} + +void tandy_eeprom_close(void *p) +{ + tandy_eeprom_t *eeprom = (tandy_eeprom_t *)p; + FILE *f; + + switch (eeprom->romset) + { + case ROM_TANDY1000HX: + f = romfopen("nvr/tandy1000hx.bin" ,"wb"); + break; + case ROM_TANDY1000SL2: + f = romfopen("nvr/tandy1000sl2.bin" ,"wb"); + break; + } + fwrite(eeprom->store, 128, 1, f); + fclose(f); + + free(eeprom); +} + +device_t tandy_eeprom_device = +{ + "Tandy EEPROM", + 0, + tandy_eeprom_init, + tandy_eeprom_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/tandy_eeprom.h b/src/tandy_eeprom.h new file mode 100644 index 000000000..c129050c8 --- /dev/null +++ b/src/tandy_eeprom.h @@ -0,0 +1,2 @@ +device_t tandy_eeprom_device; +int tandy_eeprom_read(); diff --git a/src/tandy_rom.c b/src/tandy_rom.c new file mode 100644 index 000000000..f95ca0dfb --- /dev/null +++ b/src/tandy_rom.c @@ -0,0 +1,94 @@ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "tandy_rom.h" + +static uint8_t *tandy_rom; +static uint8_t tandy_rom_bank; +static int tandy_rom_offset; +static mem_mapping_t tandy_rom_mapping; + +uint8_t tandy_read_rom(uint32_t addr, void *p) +{ + uint32_t addr2 = (addr & 0xffff) + tandy_rom_offset; +// if (!nopageerrors) pclog("tandy_read_rom: %05x %05x %02x %04x:%04x\n", addr, addr2, tandy_rom[addr2], CS,pc); + return tandy_rom[addr2]; +} +uint16_t tandy_read_romw(uint32_t addr, void *p) +{ + uint32_t addr2 = (addr & 0xffff) + tandy_rom_offset; +// if (!nopageerrors) pclog("tandy_read_romw: %05x %05x %04x %04x:%04x\n", addr, addr2, *(uint16_t *)&tandy_rom[addr2], CS,pc); + return *(uint16_t *)&tandy_rom[addr2]; +} +uint32_t tandy_read_roml(uint32_t addr, void *p) +{ + uint32_t addr2 = (addr & 0xffff) + tandy_rom_offset; +// if (!nopageerrors) pclog("tandy_read_roml: %05x %05x %08x\n", addr, addr2, *(uint32_t *)&tandy_rom[addr2]); + return *(uint32_t *)&tandy_rom[addr]; +} + +uint8_t tandy_rom_bank_read(uint16_t port, void *p) +{ + if (port == 0xffea) + return tandy_rom_bank ^ 0x10; + else + return 0xff; +} +void tandy_rom_bank_write(uint16_t port, uint8_t val, void *p) +{ + if (port == 0xffea) + { + tandy_rom_bank = val; + tandy_rom_offset = ((val ^ 4) & 7) * 0x10000; + mem_mapping_set_exec(&tandy_rom_mapping, &tandy_rom[tandy_rom_offset]); +// pclog("tandy_rom_bank_write: port=%04x val=%02x offset=%05x\n", port, val, tandy_rom_offset); + } +// else +// pclog("Bad tandy write port=%04x val=%02x\n", port, val); +} + +void *tandy_rom_init() +{ + FILE *f, *ff; + int c; + + tandy_rom = malloc(0x80000); + + f = romfopen("roms/tandy1000sl2/8079047.hu1" ,"rb"); + ff = romfopen("roms/tandy1000sl2/8079048.hu2","rb"); + for (c = 0x0000; c < 0x80000; c += 2) + { + tandy_rom[c] = getc(f); + tandy_rom[c + 1] = getc(ff); + } + fclose(ff); + fclose(f); + + mem_mapping_add(&tandy_rom_mapping, 0xe0000, 0x10000, + tandy_read_rom, tandy_read_romw, tandy_read_roml, + NULL, NULL, NULL, + tandy_rom, MEM_MAPPING_EXTERNAL, NULL); + + io_sethandler(0xffe8, 0x0008, tandy_rom_bank_read, NULL, NULL, tandy_rom_bank_write, NULL, NULL, NULL); + + return tandy_rom; +} + +void tandy_rom_close(void *p) +{ + free(p); +} + +device_t tandy_rom_device = +{ + "Tandy 1000SL/2 ROM", + 0, + tandy_rom_init, + tandy_rom_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/tandy_rom.h b/src/tandy_rom.h new file mode 100644 index 000000000..4dfbb3e71 --- /dev/null +++ b/src/tandy_rom.h @@ -0,0 +1 @@ +extern device_t tandy_rom_device; diff --git a/src/thread-pthread.c b/src/thread-pthread.c new file mode 100644 index 000000000..3a9a185db --- /dev/null +++ b/src/thread-pthread.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include "thread.h" + +typedef struct event_pthread_t +{ + pthread_cond_t cond; + pthread_mutex_t mutex; +} event_pthread_t; + +thread_t *thread_create(void (*thread_rout)(void *param), void *param) +{ + pthread_t *thread = malloc(sizeof(pthread_t)); + + pthread_create(thread, NULL, thread_rout, param); + + return thread; +} + +void thread_kill(thread_t *handle) +{ + pthread_t *thread = (pthread_t *)handle; + + pthread_cancel(*thread); + pthread_join(*thread, NULL); + + free(thread); +} + +event_t *thread_create_event() +{ + event_pthread_t *event = malloc(sizeof(event_pthread_t)); + + pthread_cond_init(&event->cond, NULL); + pthread_mutex_init(&event->mutex, NULL); + + return (event_t *)event; +} + +void thread_set_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_mutex_lock(&event->mutex); + pthread_cond_broadcast(&event->cond); + pthread_mutex_unlock(&event->mutex); +} + +void thread_reset_event(event_t *handle) +{ +} + +int thread_wait_event(event_t *handle, int timeout) +{ + event_pthread_t *event = (event_pthread_t *)handle; + struct timespec abstime; + + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_nsec += (timeout % 1000) * 1000000; + abstime.tv_sec += (timeout / 1000); + if (abstime.tv_nsec > 1000000000) + { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec++; + } + + pthread_mutex_lock(&event->mutex); + pthread_cond_timedwait(&event->cond, &event->mutex, &abstime); + pthread_mutex_unlock(&event->mutex); + + return 0; +} + +void thread_destroy_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_cond_destroy(&event->cond); + pthread_mutex_destroy(&event->mutex); + + free(event); +} + +void thread_sleep(int t) +{ + usleep(t * 1000); +} diff --git a/src/thread.h b/src/thread.h new file mode 100644 index 000000000..815b4f049 --- /dev/null +++ b/src/thread.h @@ -0,0 +1,12 @@ +typedef void thread_t; +thread_t *thread_create(void (*thread_rout)(void *param), void *param); +void thread_kill(thread_t *handle); + +typedef void event_t; +event_t *thread_create_event(); +void thread_set_event(event_t *event); +void thread_reset_event(event_t *_event); +int thread_wait_event(event_t *event, int timeout); +void thread_destroy_event(event_t *_event); + +void thread_sleep(int t); diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 000000000..45268869e --- /dev/null +++ b/src/timer.c @@ -0,0 +1,118 @@ +#include "ibm.h" + +/*#include "sound_opl.h" +#include "adlibgold.h" +#include "sound_pas16.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" +#include "sound_wss.h"*/ +#include "timer.h" + +#define TIMERS_MAX 32 + +int TIMER_USEC; + +static struct +{ + int present; + void (*callback)(void *priv); + void *priv; + int *enable; + int *count; +} timers[TIMERS_MAX]; + +int timers_present = 0; +int timer_one = 1; + +int timer_count = 0, timer_latch = 0; +int timer_start = 0; + +void timer_process() +{ + int c; + int retry; + int process = 0; + /*Get actual elapsed time*/ + int diff = timer_latch - timer_count; + int enable[TIMERS_MAX]; + + timer_latch = 0; + + for (c = 0; c < timers_present; c++) + { + enable[c] = *timers[c].enable; + if (*timers[c].enable) + { + *timers[c].count = *timers[c].count - diff; + if (*timers[c].count <= 0) + process = 1; + } + } + + if (!process) + return; + + while (1) + { + int lowest = 1, lowest_c; + + for (c = 0; c < timers_present; c++) + { + if (enable[c]) + { + if (*timers[c].count < lowest) + { + lowest = *timers[c].count; + lowest_c = c; + } + } + } + + if (lowest > 0) + break; + + timers[lowest_c].callback(timers[lowest_c].priv); + enable[lowest_c] = *timers[lowest_c].enable; + } +} + +void timer_update_outstanding() +{ + int c; + timer_latch = 0x7fffffff; + for (c = 0; c < timers_present; c++) + { + if (*timers[c].enable && *timers[c].count < timer_latch) + timer_latch = *timers[c].count; + } + timer_count = timer_latch = (timer_latch + ((1 << TIMER_SHIFT) - 1)) >> TIMER_SHIFT; +} + +void timer_reset() +{ + pclog("timer_reset\n"); + timers_present = 0; + timer_latch = timer_count = 0; +// timer_process(); +} + +int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv) +{ + if (timers_present < TIMERS_MAX) + { +// pclog("timer_add : adding timer %i\n", timers_present); + timers[timers_present].present = 1; + timers[timers_present].callback = callback; + timers[timers_present].priv = priv; + timers[timers_present].count = count; + timers[timers_present].enable = enable; + timers_present++; + return timers_present - 1; + } + return -1; +} + +void timer_set_callback(int timer, void (*callback)(void *priv)) +{ + timers[timer].callback = callback; +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 000000000..50c83e55c --- /dev/null +++ b/src/timer.h @@ -0,0 +1,58 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include "cpu.h" + +extern int timer_start; + +#define timer_start_period(cycles) \ + timer_start = cycles; + +#define timer_end_period(cycles) \ + do \ + { \ + int diff = timer_start - (cycles); \ + timer_count -= diff; \ + timer_start = cycles; \ + if (timer_count <= 0) \ + { \ + timer_process(); \ + timer_update_outstanding(); \ + } \ + } while (0) + +#define timer_clock() \ + do \ + { \ + int diff; \ + if (AT) \ + { \ + diff = timer_start - (cycles << TIMER_SHIFT); \ + timer_start = cycles << TIMER_SHIFT; \ + } \ + else \ + { \ + diff = timer_start - (cycles * xt_cpu_multi); \ + timer_start = cycles * xt_cpu_multi; \ + } \ + timer_count -= diff; \ + timer_process(); \ + timer_update_outstanding(); \ + } while (0) + +void timer_process(); +void timer_update_outstanding(); +void timer_reset(); +int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv); +void timer_set_callback(int timer, void (*callback)(void *priv)); + +#define TIMER_ALWAYS_ENABLED &timer_one + +extern int timer_count; +extern int timer_one; + +#define TIMER_SHIFT 6 + +extern int TIMER_USEC; + +#endif /*_TIMER_H_*/ diff --git a/src/um8669f.c b/src/um8669f.c new file mode 100644 index 000000000..85d527cff --- /dev/null +++ b/src/um8669f.c @@ -0,0 +1,137 @@ +/*um8669f : + + aa to 108 unlocks + next 108 write is register select (Cx?) + data read/write to 109 + 55 to 108 locks + + + + +C0 +bit 3 = LPT1 enable +bit 2 = COM2 enable +bit 1 = COM1 enable +bit 0 = FDC enable + +C1 +bits 7-6 = LPT1 mode : 11 = ECP/EPP, 01 = EPP, 10 = SPP +bit 3 = clear when LPT1 = 278 + +C3 +bits 7-6 = LPT1 DMA mode : 11 = ECP/EPP DMA1, 10 = ECP/EPP DMA3, 01 = EPP/SPP, 00 = ECP +bits 5-4 = LPT1 addr : 10 = 278/IRQ5, 01 = 3BC/IRQ7, 00 = 378/IRQ7 + +COM1 : +3f8, IRQ4 - C1 = BF, C3 = 00 +2f8, IRQ3 - C1 = BF, C3 = 03 +3e8, IRQ4 - C1 = BD, C3 = 00 +2e8, IRQ3 - B1 = BD, C3 = 03 + +COM2 : +3f8, IRQ4 - C1 = BF, C3 = 0C +2f8, IRQ3 - C1 = BF, C3 = 00 +3e8, IRQ4 - C1 = BB, C3 = 0C +2e8, IRQ3 - C1 = BB, C3 = 00 + + */ + +#include "ibm.h" + +#include "fdc.h" +#include "io.h" +#include "lpt.h" +#include "mouse_serial.h" +#include "serial.h" +#include "um8669f.h" + +static int um8669f_locked; +static int um8669f_curreg; +static uint8_t um8669f_regs[256]; + +void um8669f_write(uint16_t port, uint8_t val, void *priv) +{ + int temp; +// pclog("um8669f_write : port=%04x reg %02X = %02X locked=%i\n", port, um8669f_curreg, val, um8669f_locked); + if (um8669f_locked) + { + if (port == 0x108 && val == 0xaa) + um8669f_locked = 0; + } + else + { + if (port == 0x108) + { + if (val == 0x55) + um8669f_locked = 1; + else + um8669f_curreg = val; + } + else + { + um8669f_regs[um8669f_curreg] = val; + + fdc_remove(); + if (um8669f_regs[0xc0] & 1) + fdc_add(); + + if (um8669f_regs[0xc0] & 2) + { + temp = um8669f_regs[0xc3] & 1; /*might be & 2*/ + if (!(um8669f_regs[0xc1] & 2)) + temp |= 2; + switch (temp) + { + case 0: serial1_set(0x3f8, 4); break; + case 1: serial1_set(0x2f8, 4); break; + case 2: serial1_set(0x3e8, 4); break; + case 3: serial1_set(0x2e8, 4); break; + } + } + + if (um8669f_regs[0xc0] & 4) + { + temp = (um8669f_regs[0xc3] & 4) ? 0 : 1; /*might be & 8*/ + if (!(um8669f_regs[0xc1] & 4)) + temp |= 2; + switch (temp) + { + case 0: serial2_set(0x3f8, 3); break; + case 1: serial2_set(0x2f8, 3); break; + case 2: serial2_set(0x3e8, 3); break; + case 3: serial2_set(0x2e8, 3); break; + } + } + + mouse_serial_init(); + + lpt1_remove(); + lpt2_remove(); + temp = (um8669f_regs[0xc3] >> 4) & 3; + switch (temp) + { + case 0: lpt1_init(0x378); break; + case 1: lpt1_init(0x3bc); break; + case 2: lpt1_init(0x278); break; + } + } + } +} + +uint8_t um8669f_read(uint16_t port, void *priv) +{ +// pclog("um8669f_read : port=%04x reg %02X locked=%i\n", port, um8669f_curreg, um8669f_locked); + if (um8669f_locked) + return 0xff; + + if (port == 0x108) + return um8669f_curreg; /*???*/ + else + return um8669f_regs[um8669f_curreg]; +} + +void um8669f_init() +{ + io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, NULL); + um8669f_locked = 1; +} diff --git a/src/um8669f.h b/src/um8669f.h new file mode 100644 index 000000000..409ad51c2 --- /dev/null +++ b/src/um8669f.h @@ -0,0 +1 @@ +extern void um8669f_init(); diff --git a/src/um8881f.c b/src/um8881f.c new file mode 100644 index 000000000..29f89630f --- /dev/null +++ b/src/um8881f.c @@ -0,0 +1,70 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "um8881f.h" + +static uint8_t card_16[256]; +static uint8_t card_18[256]; + +void um8881f_write(int func, int addr, uint8_t val, void *priv) +{ +// pclog("um8881f_write : addr=%02x val=%02x %04x:%04x\n", addr, val, CS, pc); + if (addr == 0x54) + { +/* if ((card_16[0x54] ^ val) & 0x01) + { + if (val & 1) + mem_bios_set_state(0xe0000, 0x10000, 1, 1); + else + mem_bios_set_state(0xe0000, 0x10000, 0, 0); + }*/ + flushmmucache_nopc(); + } + if (addr == 0x55) + { + if ((card_16[0x55] ^ val) & 0xc0) + { +/* switch (val & 0xc0) + { + case 0x00: mem_bios_set_state(0xf0000, 0x10000, 0, 1); break; + case 0x40: mem_bios_set_state(0xf0000, 0x10000, 0, 0); break; + case 0x80: mem_bios_set_state(0xf0000, 0x10000, 1, 1); break; + case 0xc0: mem_bios_set_state(0xf0000, 0x10000, 1, 0); break; + }*/ + shadowbios = val & 0x80; + shadowbios_write = !(val & 0x40); + flushmmucache_nopc(); + } + } + if (addr >= 4) + card_16[addr] = val; +} + +uint8_t um8881f_read(int func, int addr, void *priv) +{ + return card_16[addr]; +} + +void um8886f_write(int func, int addr, uint8_t val, void *priv) +{ + if (addr >= 4) + card_18[addr] = val; +} + +uint8_t um8886f_read(int func, int addr, void *priv) +{ + return card_18[addr]; +} + +void um8881f_init() +{ + pci_add_specific(16, um8881f_read, um8881f_write, NULL); + pci_add_specific(18, um8886f_read, um8886f_write, NULL); + + card_16[0] = card_18[0] = 0x60; /*UMC*/ + card_16[1] = card_18[1] = 0x10; + card_16[2] = 0x81; card_16[3] = 0x88; /*UM8881 Host - PCI bridge*/ + card_18[2] = 0x86; card_18[3] = 0x88; /*UM8886 PCI - ISA bridge*/ +} diff --git a/src/um8881f.h b/src/um8881f.h new file mode 100644 index 000000000..7411a742f --- /dev/null +++ b/src/um8881f.h @@ -0,0 +1 @@ +void um8881f_init(); diff --git a/src/vid_ati18800.c b/src/vid_ati18800.c new file mode 100644 index 000000000..cf8003ef1 --- /dev/null +++ b/src/vid_ati18800.c @@ -0,0 +1,199 @@ +/*ATI 18800 emulation (VGA Edge-16)*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_ati18800.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" + +typedef struct ati18800_t +{ + svga_t svga; + ati_eeprom_t eeprom; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; +} ati18800_t; + +void ati18800_out(uint16_t addr, uint8_t val, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + svga_t *svga = &ati18800->svga; + uint8_t old; + +// pclog("ati18800_out : %04X %02X %04X:%04X\n", addr, val, CS,cpu_state.pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati18800->index = val; + break; + case 0x1cf: + ati18800->regs[ati18800->index] = val; + switch (ati18800->index) + { + case 0xb2: + case 0xbe: + if (ati18800->regs[0xbe] & 8) /*Read/write bank mode*/ + { + svga->read_bank = ((ati18800->regs[0xb2] >> 5) & 7) * 0x10000; + svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svga->read_bank = svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + break; + case 0xb3: + ati_eeprom_write(&ati18800->eeprom, val & 8, val & 2, val & 1); + break; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t ati18800_in(uint16_t addr, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + svga_t *svga = &ati18800->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("ati18800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati18800->index; + break; + case 0x1cf: + switch (ati18800->index) + { + case 0xb7: + temp = ati18800->regs[ati18800->index] & ~8; + if (ati_eeprom_read(&ati18800->eeprom)) + temp |= 8; + break; + + default: + temp = ati18800->regs[ati18800->index]; + break; + } + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } +#ifndef RELEASE_BUILD + if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); +#endif + return temp; +} + +void *ati18800_init() +{ + ati18800_t *ati18800 = malloc(sizeof(ati18800_t)); + memset(ati18800, 0, sizeof(ati18800_t)); + + rom_init(&ati18800->bios_rom, "roms/vgaedge16.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ + NULL, + ati18800_in, ati18800_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + io_sethandler(0x03c0, 0x0020, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + + ati18800->svga.miscout = 1; + + ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0); + + return ati18800; +} + +static int ati18800_available() +{ + return rom_present("roms/vgaedge16.vbi"); +} + +void ati18800_close(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_close(&ati18800->svga); + + free(ati18800); +} + +void ati18800_speed_changed(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_recalctimings(&ati18800->svga); +} + +void ati18800_force_redraw(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + ati18800->svga.fullchange = changeframecount; +} + +void ati18800_add_status_info(char *s, int max_len, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_add_status_info(s, max_len, &ati18800->svga); +} + +device_t ati18800_device = +{ + "ATI-18800", + 0, + ati18800_init, + ati18800_close, + ati18800_available, + ati18800_speed_changed, + ati18800_force_redraw, + ati18800_add_status_info +}; + diff --git a/src/vid_ati18800.h b/src/vid_ati18800.h new file mode 100644 index 000000000..6cdd2366b --- /dev/null +++ b/src/vid_ati18800.h @@ -0,0 +1 @@ +extern device_t ati18800_device; diff --git a/src/vid_ati28800.c b/src/vid_ati28800.c new file mode 100644 index 000000000..aa7a33afd --- /dev/null +++ b/src/vid_ati28800.c @@ -0,0 +1,279 @@ +/*ATI 28800 emulation (VGA Charger)*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_ati28800.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +typedef struct ati28800_t +{ + svga_t svga; + ati_eeprom_t eeprom; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; +} ati28800_t; + +void ati28800_out(uint16_t addr, uint8_t val, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t old; + +// pclog("ati28800_out : %04X %02X %04X:%04X\n", addr, val, CS,cpu_state.pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati28800->index = val; + break; + case 0x1cf: + ati28800->regs[ati28800->index] = val; + switch (ati28800->index) + { + case 0xb2: + case 0xbe: + if (ati28800->regs[0xbe] & 8) /*Read/write bank mode*/ + { + svga->read_bank = ((ati28800->regs[0xb2] >> 5) & 7) * 0x10000; + svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svga->read_bank = svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; + break; + case 0xb3: + ati_eeprom_write(&ati28800->eeprom, val & 8, val & 2, val & 1); + break; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t ati28800_in(uint16_t addr, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("ati28800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati28800->index; + break; + case 0x1cf: + switch (ati28800->index) + { + case 0xb7: + temp = ati28800->regs[ati28800->index] & ~8; + if (ati_eeprom_read(&ati28800->eeprom)) + temp |= 8; + break; + + default: + temp = ati28800->regs[ati28800->index]; + break; + } + break; + + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; + break; + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } +#ifndef RELEASE_BUILD + if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); +#endif + return temp; +} + +void ati28800_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *)svga->p; +#ifndef RELEASE_BUILD + pclog("ati28800_recalctimings\n"); +#endif + if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + { +#ifndef RELEASE_BUILD + pclog("8bpp_highres\n"); +#endif + svga->render = svga_render_8bpp_highres; + svga->rowoffset <<= 1; + svga->ma <<= 1; + } +} + +void *ati28800_init() +{ + uint32_t memory = 512; + if (gfxcard == GFX_VGAWONDERXL) device_get_config_int("memory"); + memory <<= 10; + ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); + memset(ati28800, 0, sizeof(ati28800_t)); + + if (gfxcard == GFX_VGAWONDERXL) + { + rom_init_interleaved(&ati28800->bios_rom, + "roms/XLEVEN.BIN", + "roms/XLODD.BIN", + 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + } + else + rom_init(&ati28800->bios_rom, "roms/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&ati28800->svga, ati28800, memory, /*512kb*/ + ati28800_recalctimings, + ati28800_in, ati28800_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati28800_in, NULL, NULL, ati28800_out, NULL, NULL, ati28800); + io_sethandler(0x03c0, 0x0020, ati28800_in, NULL, NULL, ati28800_out, NULL, NULL, ati28800); + + ati28800->svga.miscout = 1; + + ati_eeprom_load(&ati28800->eeprom, "ati28800.nvr", 0); + + return ati28800; +} + +static int ati28800_available() +{ + return rom_present("roms/bios.bin"); +} + +static int compaq_ati28800_available() +{ + return (rom_present("roms/XLEVEN.bin") && rom_present("roms/XLODD.bin")); +} + +void ati28800_close(void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + svga_close(&ati28800->svga); + + free(ati28800); +} + +void ati28800_speed_changed(void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + svga_recalctimings(&ati28800->svga); +} + +void ati28800_force_redraw(void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + ati28800->svga.fullchange = changeframecount; +} + +void ati28800_add_status_info(char *s, int max_len, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + svga_add_status_info(s, max_len, &ati28800->svga); +} + +static device_config_t compaq_ati28800_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + }, + .default_int = 512 + }, + { + .type = -1 + } +}; + +device_t ati28800_device = +{ + "ATI-28800", + 0, + ati28800_init, + ati28800_close, + ati28800_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_add_status_info +}; + +device_t compaq_ati28800_device = +{ + "Compaq ATI-28800", + 0, + ati28800_init, + ati28800_close, + compaq_ati28800_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_add_status_info, + compaq_ati28800_config +}; diff --git a/src/vid_ati28800.h b/src/vid_ati28800.h new file mode 100644 index 000000000..68f488783 --- /dev/null +++ b/src/vid_ati28800.h @@ -0,0 +1,2 @@ +extern device_t ati28800_device; +extern device_t compaq_ati28800_device; diff --git a/src/vid_ati68860_ramdac.c b/src/vid_ati68860_ramdac.c new file mode 100644 index 000000000..273c9673e --- /dev/null +++ b/src/vid_ati68860_ramdac.c @@ -0,0 +1,176 @@ +/*ATI 68860 RAMDAC emulation (for Mach64)*/ +/* +ATI 68860/68880 Truecolor DACs: +REG08 (R/W): +bit 0-? Always 2 ?? + +REG0A (R/W): +bit 0-? Always 1Dh ?? + +REG0B (R/W): (GMR ?) +bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, A0h: 15bpp, A1h: 16bpp, C0h: 24bpp, + E3h: 32bpp (80h for VGA modes ?) + +REG0C (R/W): Device Setup Register A +bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT + 2-3 Depends on Video memory (= VRAM width ?) . 1: Less than 1Mb, 2: 1Mb, + 3: > 1Mb + 5-6 Always set ? + 7 If set can remove "snow" in some cases (A860_Delay_L ?) ?? +*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_svga_render.h" + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) +{ +// pclog("ati68860_out : addr %04X val %02X %04X:%04X\n", addr, val, CS,pc); + switch (addr) + { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + default: + ramdac->regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0x4: + ramdac->dac_write = val; + ramdac->dac_pos = 0; + break; + case 0x5: + switch (ramdac->dac_pos) + { + case 0: + ramdac->dac_r = val; + ramdac->dac_pos++; + break; + case 1: + ramdac->dac_g = val; + ramdac->dac_pos++; + break; + case 2: + if (ramdac->dac_write > 1) + break; + ramdac->pal[ramdac->dac_write].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_write].g = ramdac->dac_g; + ramdac->pal[ramdac->dac_write].b = val; + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[ramdac->dac_write] = makecol32(ramdac->pal[ramdac->dac_write].r, ramdac->pal[ramdac->dac_write].g, ramdac->pal[ramdac->dac_write].b); + else + ramdac->pallook[ramdac->dac_write] = makecol32((ramdac->pal[ramdac->dac_write].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].b & 0x3f) * 4); + ramdac->dac_pos = 0; + ramdac->dac_write = (ramdac->dac_write + 1) & 255; + break; + } + break; + + case 0xb: + switch (val) + { + case 0x82: + ramdac->render = svga_render_4bpp_highres; + break; + case 0x83: + ramdac->render = svga_render_8bpp_highres; + break; + case 0xa0: case 0xb0: + ramdac->render = svga_render_15bpp_highres; + break; + case 0xa1: case 0xb1: + ramdac->render = svga_render_16bpp_highres; + break; + case 0xc0: case 0xd0: + ramdac->render = svga_render_24bpp_highres; + break; + case 0xe2: case 0xf7: + ramdac->render = svga_render_32bpp_highres; + break; + case 0xe3: + ramdac->render = svga_render_ABGR8888_highres; + break; + case 0xf2: + ramdac->render = svga_render_RGBA8888_highres; + break; + default: + ramdac->render = svga_render_8bpp_highres; + break; + } + break; + case 0xc: + svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT); + break; + } + break; + } +} + +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t ret = 0; + switch (addr) + { + case 0: + ret = svga_in(0x3c8, svga); + break; + case 1: + ret = svga_in(0x3c9, svga); + break; + case 2: + ret = svga_in(0x3c6, svga); + break; + case 3: + ret = svga_in(0x3c7, svga); + break; + case 4: case 8: + ret = 2; + break; + case 6: case 0xa: + ret = 0x1d; + break; + case 0xf: + ret = 0xd0; + break; + + default: + ret = ramdac->regs[addr & 0xf]; + break; + } +// pclog("ati68860_in : addr %04X ret %02X %04X:%04X\n", addr, ret, CS,pc); + return ret; +} + +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac) +{ + ramdac->render = svga_render_8bpp_highres; +} + +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type) +{ + int c; + + if (ramdac->ramdac_type != type) + { + ramdac->ramdac_type = type; + + for (c = 0; c < 2; c++) + { + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g, ramdac->pal[c].b); + else + ramdac->pallook[c] = makecol32((ramdac->pal[c].r & 0x3f) * 4, (ramdac->pal[c].g & 0x3f) * 4, (ramdac->pal[c].b & 0x3f) * 4); + } + } +} diff --git a/src/vid_ati68860_ramdac.h b/src/vid_ati68860_ramdac.h new file mode 100644 index 000000000..9add13a62 --- /dev/null +++ b/src/vid_ati68860_ramdac.h @@ -0,0 +1,17 @@ +typedef struct ati68860_ramdac_t +{ + uint8_t regs[16]; + void (*render)(struct svga_t *svga); + + int dac_write, dac_pos; + int dac_r, dac_g; + PALETTE pal; + uint32_t pallook[2]; + + int ramdac_type; +} ati68860_ramdac_t; + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga); +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga); +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac); +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type); diff --git a/src/vid_ati_eeprom.c b/src/vid_ati_eeprom.c new file mode 100644 index 000000000..285f90878 --- /dev/null +++ b/src/vid_ati_eeprom.c @@ -0,0 +1,220 @@ +#include "ibm.h" +#include "vid_ati_eeprom.h" + +enum +{ + EEPROM_IDLE, + EEPROM_WAIT, + EEPROM_OPCODE, + EEPROM_INPUT, + EEPROM_OUTPUT +}; + +enum +{ + EEPROM_OP_EW = 4, + EEPROM_OP_WRITE = 5, + EEPROM_OP_READ = 6, + EEPROM_OP_ERASE = 7, + + EEPROM_OP_WRALMAIN = -1 +}; + +enum +{ + EEPROM_OP_EWDS = 0, + EEPROM_OP_WRAL = 1, + EEPROM_OP_ERAL = 2, + EEPROM_OP_EWEN = 3 +}; + +void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type) +{ + FILE *f; + eeprom->type = type; + strcpy(eeprom->fn, fn); + f = romfopen(eeprom->fn, "rb"); + if (!f) + { + memset(eeprom->data, 0, eeprom->type ? 512 : 128); + return; + } + fread(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_save(ati_eeprom_t *eeprom) +{ + FILE *f = romfopen(eeprom->fn, "wb"); + if (!f) return; + fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) +{ + int c; +// pclog("EEPROM write %i %i %i\n", ena, clk, dat); + if (!ena) + { + eeprom->out = 1; + } + if (clk && !eeprom->oldclk) + { + if (ena && !eeprom->oldena) + { + eeprom->state = EEPROM_WAIT; + eeprom->opcode = 0; + eeprom->count = 3; + eeprom->out = 1; + } + else if (ena) + { +// pclog("EEPROM receive %i %i %i\n", ena, clk, dat); + switch (eeprom->state) + { + case EEPROM_WAIT: + if (!dat) + break; + eeprom->state = EEPROM_OPCODE; + /* fall through */ + case EEPROM_OPCODE: + eeprom->opcode = (eeprom->opcode << 1) | (dat ? 1 : 0); + eeprom->count--; + if (!eeprom->count) + { +// pclog("EEPROM opcode - %i\n", eeprom->opcode); + switch (eeprom->opcode) + { + case EEPROM_OP_WRITE: + eeprom->count = eeprom->type ? 24 : 22; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_READ: + eeprom->count = eeprom->type ? 8 : 6; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_EW: + eeprom->count = 2; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_ERASE: + eeprom->count = eeprom->type ? 8 : 6; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + } + } + break; + + case EEPROM_INPUT: + eeprom->dat = (eeprom->dat << 1) | (dat ? 1 : 0); + eeprom->count--; + if (!eeprom->count) + { +// pclog("EEPROM dat - %02X\n", eeprom->dat); + switch (eeprom->opcode) + { + case EEPROM_OP_WRITE: +// pclog("EEPROM_OP_WRITE addr %02X eeprom_dat %04X\n", (eeprom->dat >> 16) & (eeprom->type ? 255 : 63), eeprom->dat & 0xffff); + if (!eeprom->wp) + { + eeprom->data[(eeprom->dat >> 16) & (eeprom->type ? 255 : 63)] = eeprom->dat & 0xffff; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_READ: + eeprom->count = 17; + eeprom->state = EEPROM_OUTPUT; + eeprom->dat = eeprom->data[eeprom->dat]; +// pclog("Trigger EEPROM_OUTPUT %04X\n", eeprom->dat); + break; + case EEPROM_OP_EW: +// pclog("EEPROM_OP_EW %i\n", eeprom->dat); + switch (eeprom->dat) + { + case EEPROM_OP_EWDS: + eeprom->wp = 1; + break; + case EEPROM_OP_WRAL: + eeprom->opcode = EEPROM_OP_WRALMAIN; + eeprom->count = 20; + break; + case EEPROM_OP_ERAL: + if (!eeprom->wp) + { + memset(eeprom->data, 0xff, 128); + ati_eeprom_save(eeprom); + } + break; + case EEPROM_OP_EWEN: + eeprom->wp = 0; + break; + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_ERASE: +// pclog("EEPROM_OP_ERASE %i\n", eeprom->dat); + if (!eeprom->wp) + { + eeprom->data[eeprom->dat] = 0xffff; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_WRALMAIN: +// pclog("EEPROM_OP_WRAL %04X\n", eeprom->dat); + if (!eeprom->wp) + { + for (c = 0; c < 256; c++) + eeprom->data[c] = eeprom->dat; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + } + } + break; + } + } + eeprom->oldena = ena; + } + else if (!clk && eeprom->oldclk) + { + if (ena) + { + switch (eeprom->state) + { + case EEPROM_OUTPUT: + eeprom->out = (eeprom->dat & 0x10000) ? 1 : 0; + eeprom->dat <<= 1; +// pclog("EEPROM_OUTPUT - data %i\n", eeprom->out); + eeprom->count--; + if (!eeprom->count) + { +// pclog("EEPROM_OUTPUT complete\n"); + eeprom->state = EEPROM_IDLE; + } + break; + } + } + } + eeprom->oldclk = clk; +} + +int ati_eeprom_read(ati_eeprom_t *eeprom) +{ + return eeprom->out; +} + diff --git a/src/vid_ati_eeprom.h b/src/vid_ati_eeprom.h new file mode 100644 index 000000000..63adf19ef --- /dev/null +++ b/src/vid_ati_eeprom.h @@ -0,0 +1,16 @@ +typedef struct ati_eeprom_t +{ + uint16_t data[256]; + + int oldclk, oldena; + int opcode, state, count, out; + int wp; + uint32_t dat; + int type; + + char fn[256]; +} ati_eeprom_t; + +void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type); +void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat); +int ati_eeprom_read(ati_eeprom_t *eeprom); diff --git a/src/vid_ati_mach64.c b/src/vid_ati_mach64.c new file mode 100644 index 000000000..2add828ce --- /dev/null +++ b/src/vid_ati_mach64.c @@ -0,0 +1,2731 @@ +/*ATI Mach64 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_ati_eeprom.h" +#include "vid_ics2595.h" + +//#define MACH64_DEBUG + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (mach64->fifo_write_idx - mach64->fifo_read_idx) +#define FIFO_FULL ((mach64->fifo_write_idx - mach64->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (mach64->fifo_read_idx == mach64->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct mach64_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + mem_mapping_t mmio_linear_mapping; + + ati68860_ramdac_t ramdac; + ati_eeprom_t eeprom; + ics2595_t ics2595; + svga_t svga; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; + + uint8_t pci_regs[256]; + + int bank_r[2]; + int bank_w[2]; + + uint32_t vram_size; + uint32_t vram_mask; + + uint32_t config_cntl; + + uint32_t context_load_cntl; + uint32_t context_mask; + + uint32_t crtc_gen_cntl; + uint8_t crtc_int_cntl; + uint32_t crtc_h_total_disp; + uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_off_pitch; + + uint32_t clock_cntl; + + uint32_t clr_cmp_clr; + uint32_t clr_cmp_cntl; + uint32_t clr_cmp_mask; + + uint32_t cur_horz_vert_off; + uint32_t cur_horz_vert_posn; + uint32_t cur_offset; + + uint32_t dac_cntl; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + uint32_t dp_mix; + uint32_t dp_pix_width; + uint32_t dp_src; + + uint32_t dst_bres_lnth; + uint32_t dst_bres_dec; + uint32_t dst_bres_err; + uint32_t dst_bres_inc; + + uint32_t dst_cntl; + uint32_t dst_height_width; + uint32_t dst_off_pitch; + uint32_t dst_y_x; + + uint32_t gen_test_cntl; + + uint32_t gui_traj_cntl; + + uint32_t mem_cntl; + + uint32_t ovr_clr; + uint32_t ovr_wid_left_right; + uint32_t ovr_wid_top_bottom; + + uint32_t pat_cntl; + uint32_t pat_reg0, pat_reg1; + + uint32_t sc_left_right, sc_top_bottom; + + uint32_t scratch_reg0, scratch_reg1; + + uint32_t src_cntl; + uint32_t src_off_pitch; + uint32_t src_y_x; + uint32_t src_y_x_start; + uint32_t src_height1_width1, src_height2_width2; + + + uint32_t linear_base, old_linear_base; + + struct + { + int op; + + int dst_x, dst_y; + int dst_x_start, dst_y_start; + int src_x, src_y; + int src_x_start, src_y_start; + int xinc, yinc; + int x_count, y_count; + int src_x_count, src_y_count; + int src_width1, src_height1; + int src_width2, src_height2; + uint32_t src_offset, src_pitch; + uint32_t dst_offset, dst_pitch; + int mix_bg, mix_fg; + int source_bg, source_fg, source_mix; + int source_host; + int dst_width, dst_height; + int busy; + int pattern[8][8]; + int sc_left, sc_right, sc_top, sc_bottom; + int dst_pix_width, src_pix_width, host_pix_width; + int dst_size, src_size, host_size; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + + uint32_t clr_cmp_clr; + uint32_t clr_cmp_mask; + int clr_cmp_fn; + int clr_cmp_src; + + int err; + int poly_draw; + } accel; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; +} mach64_t; + +enum +{ + SRC_BG = 0, + SRC_FG = 1, + SRC_HOST = 2, + SRC_BLITSRC = 3, + SRC_PAT = 4 +}; + +enum +{ + MONO_SRC_1 = 0, + MONO_SRC_PAT = 1, + MONO_SRC_HOST = 2, + MONO_SRC_BLITSRC = 3 +}; + +enum +{ + BPP_1 = 0, + BPP_4 = 1, + BPP_8 = 2, + BPP_15 = 3, + BPP_16 = 4, + BPP_32 = 5 +}; + +enum +{ + OP_RECT, + OP_LINE +}; + +enum +{ + SRC_PATT_EN = 1, + SRC_PATT_ROT_EN = 2, + SRC_LINEAR_EN = 4 +}; + +enum +{ + DP_BYTE_PIX_ORDER = (1 << 24) +}; + +#define WIDTH_1BIT 3 + +static int mach64_width[8] = {WIDTH_1BIT, 0, 0, 1, 1, 2, 2, 0}; + +enum +{ + DST_X_DIR = 0x01, + DST_Y_DIR = 0x02, + DST_Y_MAJOR = 0x04, + DST_X_TILE = 0x08, + DST_Y_TILE = 0x10, + DST_LAST_PEL = 0x20, + DST_POLYGON_EN = 0x40, + DST_24_ROT_EN = 0x80 +}; + +void mach64_write(uint32_t addr, uint8_t val, void *priv); +uint8_t mach64_read(uint32_t addr, void *priv); +void mach64_updatemapping(mach64_t *mach64); +void mach64_recalctimings(svga_t *svga); +void mach64_start_fill(mach64_t *mach64); +void mach64_start_line(mach64_t *mach64); +void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64); +void mach64_load_context(mach64_t *mach64); + +uint8_t mach64_ext_readb(uint32_t addr, void *priv); +uint16_t mach64_ext_readw(uint32_t addr, void *priv); +uint32_t mach64_ext_readl(uint32_t addr, void *priv); +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv); +void mach64_ext_writew(uint32_t addr, uint16_t val, void *priv); +void mach64_ext_writel(uint32_t addr, uint32_t val, void *priv); + +void mach64_out(uint16_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = p; + svga_t *svga = &mach64->svga; + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("mach64 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x1ce: + mach64->index = val; + break; + case 0x1cf: + mach64->regs[mach64->index & 0x3f] = val; + if ((mach64->index & 0x3f) == 0x36) + mach64_recalctimings(svga); + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, svga); + return; + + case 0x3cf: + if (svga->gdcaddr == 6) + { + uint8_t old_val = svga->gdcreg[6]; + svga->gdcreg[6] = val; + if ((svga->gdcreg[6] & 0xc) != (old_val & 0xc)) + mach64_updatemapping(mach64); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg > 0x18) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old!=val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t mach64_in(uint16_t addr, void *p) +{ + mach64_t *mach64 = p; + svga_t *svga = &mach64->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + +// pclog("IN mach64 %04X\n", addr); + + switch (addr) + { + case 0x1ce: + return mach64->index; + case 0x1cf: + return mach64->regs[mach64->index & 0x3f]; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, svga); + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x18) + return 0xff; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void mach64_recalctimings(svga_t *svga) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + { + svga->vtotal = (mach64->crtc_v_total_disp & 2047) + 1; + svga->dispend = ((mach64->crtc_v_total_disp >> 16) & 2047) + 1; + svga->htotal = (mach64->crtc_h_total_disp & 255) + 1; + svga->hdisp_time = svga->hdisp = ((mach64->crtc_h_total_disp >> 16) & 255) + 1; + svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1; + svga->rowoffset = (mach64->crtc_off_pitch >> 22); + svga->clock = cpuclock / mach64->ics2595.output_clock; + svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; + svga->linedbl = svga->rowcount = 0; + svga->split = 0xffffff; + svga->vblankstart = svga->dispend; +// svga_htotal <<= 1; +// svga_hdisp <<= 1; + svga->rowoffset <<= 1; + svga->render = mach64->ramdac.render; + switch ((mach64->crtc_gen_cntl >> 8) & 7) + { + case 1: +// svga->render = svga_render_4bpp_highres; + svga->hdisp *= 8; + break; + case 2: +// svga->render = svga_render_8bpp_highres; + svga->hdisp *= 8; + svga->rowoffset /= 2; + break; + case 3: +// svga->render = svga_render_15bpp_highres; + svga->hdisp *= 8; + //svga_rowoffset *= 2; + break; + case 4: +// svga->render = svga_render_16bpp_highres; + svga->hdisp *= 8; + //svga_rowoffset *= 2; + break; + case 5: +// svga->render = svga_render_24bpp_highres; + svga->hdisp *= 8; + svga->rowoffset = (svga->rowoffset * 3) / 2; + break; + case 6: +// svga->render = svga_render_32bpp_highres; + svga->hdisp *= 8; + svga->rowoffset *= 2; + break; + } + + svga->vrammask = mach64->vram_mask; +// pclog("mach64_recalctimings : frame %i,%i disp %i,%i vsync at %i rowoffset %i pixel clock %f MA %08X\n", svga->htotal, svga->vtotal, svga->hdisp, svga->dispend, svga->vsyncstart, svga->rowoffset, svga->clock, svga->ma); + } + else + { + svga->vrammask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff; + } +} + +void mach64_updatemapping(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + + if (!(mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&mach64->linear_mapping); + mem_mapping_disable(&mach64->mmio_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping); + return; + } + + mem_mapping_disable(&mach64->mmio_mapping); +// pclog("Write mapping %02X\n", val); + switch (svga->gdcreg[6] & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, NULL, NULL, mach64_write, NULL, NULL); + mem_mapping_set_p(&mach64->svga.mapping, mach64); + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_enable(&mach64->mmio_mapping); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, NULL, NULL, mach64_write, NULL, NULL); + mem_mapping_set_p(&mach64->svga.mapping, mach64); + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_p(&mach64->svga.mapping, svga); + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_p(&mach64->svga.mapping, svga); + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + if (mach64->linear_base) + { + if ((mach64->config_cntl & 3) == 2) + { + /*8 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); + } + else + { + /*4 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (4 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((4 << 20) - 0x4000), 0x4000); + } + } + else + { + mem_mapping_disable(&mach64->linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping); + } +} + +static inline void wake_fifo_thread(mach64_t *mach64) +{ + thread_set_event(mach64->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void mach64_wait_fifo_idle(mach64_t *mach64) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(mach64); + thread_wait_event(mach64->fifo_not_full_event, 1); + } +} + +#define READ8(addr, var) switch ((addr) & 3) \ + { \ + case 0: ret = (var) & 0xff; break; \ + case 1: ret = ((var) >> 8) & 0xff; break; \ + case 2: ret = ((var) >> 16) & 0xff; break; \ + case 3: ret = ((var) >> 24) & 0xff; break; \ + } + +#define WRITE8(addr, var, val) switch ((addr) & 3) \ + { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + +static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) +{ +// pclog("mach64_accel_write_fifo: addr=%08x val=%02x\n", addr, val); + switch (addr & 0x3ff) + { + case 0x100: case 0x101: case 0x102: case 0x103: + WRITE8(addr, mach64->dst_off_pitch, val); + break; + case 0x104: case 0x105: case 0x11c: case 0x11d: + WRITE8(addr + 2, mach64->dst_y_x, val); + break; + case 0x108: case 0x109: + WRITE8(addr, mach64->dst_y_x, val); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + WRITE8(addr, mach64->dst_y_x, val); + break; + case 0x110: case 0x111: + WRITE8(addr + 2, mach64->dst_height_width, val); + break; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + WRITE8(addr, mach64->dst_height_width, val); + case 0x113: + if ((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f || + ((addr & 0x3ff) == 0x113) && !(val & 0x80)) + { + mach64_start_fill(mach64); +#ifdef MACH64_DEBUG + pclog("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000), + ((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST), + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST), mach64->dp_src); +#endif + if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1, mach64); + } + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + WRITE8(addr, mach64->dst_bres_lnth, val); + if ((addr & 0x3ff) == 0x123 && !(val & 0x80)) + { + mach64_start_line(mach64); + + if ((mach64->dst_bres_lnth & 0x7fff) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1, mach64); + } + break; + case 0x124: case 0x125: case 0x126: case 0x127: + WRITE8(addr, mach64->dst_bres_err, val); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + WRITE8(addr, mach64->dst_bres_inc, val); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + WRITE8(addr, mach64->dst_bres_dec, val); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + WRITE8(addr, mach64->dst_cntl, val); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + WRITE8(addr, mach64->src_off_pitch, val); + break; + case 0x184: case 0x185: + WRITE8(addr, mach64->src_y_x, val); + break; + case 0x188: case 0x189: + WRITE8(addr + 2, mach64->src_y_x, val); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + WRITE8(addr, mach64->src_y_x, val); + break; + case 0x190: case 0x191: + WRITE8(addr + 2, mach64->src_height1_width1, val); + break; + case 0x194: case 0x195: + WRITE8(addr, mach64->src_height1_width1, val); + break; + case 0x198: case 0x199: case 0x19a: case 0x19b: + WRITE8(addr, mach64->src_height1_width1, val); + break; + case 0x19c: case 0x19d: + WRITE8(addr, mach64->src_y_x_start, val); + break; + case 0x1a0: case 0x1a1: + WRITE8(addr + 2, mach64->src_y_x_start, val); + break; + case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: + WRITE8(addr, mach64->src_y_x_start, val); + break; + case 0x1a8: case 0x1a9: + WRITE8(addr + 2, mach64->src_height2_width2, val); + break; + case 0x1ac: case 0x1ad: + WRITE8(addr, mach64->src_height2_width2, val); + break; + case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: + WRITE8(addr, mach64->src_height2_width2, val); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + WRITE8(addr, mach64->src_cntl, val); + break; + + case 0x200: case 0x201: case 0x202: case 0x203: + case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20a: case 0x20b: + case 0x20c: case 0x20d: case 0x20e: case 0x20f: + case 0x210: case 0x211: case 0x212: case 0x213: + case 0x214: case 0x215: case 0x216: case 0x217: + case 0x218: case 0x219: case 0x21a: case 0x21b: + case 0x21c: case 0x21d: case 0x21e: case 0x21f: + case 0x220: case 0x221: case 0x222: case 0x223: + case 0x224: case 0x225: case 0x226: case 0x227: + case 0x228: case 0x229: case 0x22a: case 0x22b: + case 0x22c: case 0x22d: case 0x22e: case 0x22f: + case 0x230: case 0x231: case 0x232: case 0x233: + case 0x234: case 0x235: case 0x236: case 0x237: + case 0x238: case 0x239: case 0x23a: case 0x23b: + case 0x23c: case 0x23d: case 0x23e: case 0x23f: + mach64_blit(val, 8, mach64); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + WRITE8(addr, mach64->pat_reg0, val); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + WRITE8(addr, mach64->pat_reg1, val); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + WRITE8(addr, mach64->sc_left_right, val); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + WRITE8(addr, mach64->sc_left_right, val); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + WRITE8(addr, mach64->sc_top_bottom, val); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + WRITE8(addr, mach64->sc_top_bottom, val); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + WRITE8(addr, mach64->dp_bkgd_clr, val); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + WRITE8(addr, mach64->dp_frgd_clr, val); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + WRITE8(addr, mach64->dp_pix_width, val); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + WRITE8(addr, mach64->dp_mix, val); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + WRITE8(addr, mach64->dp_src, val); + break; + + case 0x300: case 0x301: case 0x302: case 0x303: + WRITE8(addr, mach64->clr_cmp_clr, val); + break; + case 0x304: case 0x305: case 0x306: case 0x307: + WRITE8(addr, mach64->clr_cmp_mask, val); + break; + case 0x308: case 0x309: case 0x30a: case 0x30b: + WRITE8(addr, mach64->clr_cmp_cntl, val); + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + WRITE8(addr, mach64->context_mask, val); + break; + + case 0x330: case 0x331: + WRITE8(addr, mach64->dst_cntl, val); + break; + case 0x332: + WRITE8(addr - 2, mach64->src_cntl, val); + break; + case 0x333: + WRITE8(addr - 3, mach64->pat_cntl, val & 7); + break; + } +} +static void mach64_accel_write_fifo_w(mach64_t *mach64, uint32_t addr, uint16_t val) +{ +// pclog("mach64_accel_write_fifo_w: addr=%08x val=%04x\n", addr, val); + switch (addr & 0x3fe) + { + case 0x200: case 0x202: case 0x204: case 0x206: + case 0x208: case 0x20a: case 0x20c: case 0x20e: + case 0x210: case 0x212: case 0x214: case 0x216: + case 0x218: case 0x21a: case 0x21c: case 0x21e: + case 0x220: case 0x222: case 0x224: case 0x226: + case 0x228: case 0x22a: case 0x22c: case 0x22e: + case 0x230: case 0x232: case 0x234: case 0x236: + case 0x238: case 0x23a: case 0x23c: case 0x23e: + mach64_blit(val, 16, mach64); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_accel_write_fifo(mach64, addr, val); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_accel_write_fifo(mach64, addr + 1, val >> 8); + break; + } +} +static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t val) +{ +// pclog("mach64_accel_write_fifo_l: addr=%08x %02x val=%08x\n", addr, addr >> 2, val); + switch (addr & 0x3fc) + { + case 0x32c: + mach64->context_load_cntl = val; + if (val & 0x30000) + mach64_load_context(mach64); + break; + + case 0x200: case 0x204: case 0x208: case 0x20c: + case 0x210: case 0x214: case 0x218: case 0x21c: + case 0x220: case 0x224: case 0x228: case 0x22c: + case 0x230: case 0x234: case 0x238: case 0x23c: + if (mach64->accel.source_host || (mach64->dp_pix_width & DP_BYTE_PIX_ORDER)) + mach64_blit(val, 32, mach64); + else + mach64_blit(((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), 32, mach64); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_accel_write_fifo_w(mach64, addr, val); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_accel_write_fifo_w(mach64, addr + 2, val >> 16); + break; + } +} + +static void fifo_thread(void *param) +{ + mach64_t *mach64 = (mach64_t *)param; + + while (1) + { + thread_set_event(mach64->fifo_not_full_event); + thread_wait_event(mach64->wake_fifo_thread, -1); + thread_reset_event(mach64->wake_fifo_thread); + mach64->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + mach64_accel_write_fifo(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + mach64_accel_write_fifo_w(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + mach64_accel_write_fifo_l(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + mach64->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(mach64->fifo_not_full_event); + + end_time = timer_read(); + mach64->blitter_time += end_time - start_time; + } + mach64->blitter_busy = 0; + } +} + +static void mach64_queue(mach64_t *mach64, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(mach64->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(mach64->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + mach64->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(mach64); +} + +void mach64_cursor_dump(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; +/* pclog("Mach64 cursor :\n"); + pclog("Ena = %i X = %i Y = %i Addr = %05X Xoff = %i Yoff = %i\n", svga->hwcursor.ena, svga->hwcursor.x, svga->hwcursor.y, svga->hwcursor.addr, svga->hwcursor.xoff, svga->hwcursor.yoff);*/ +} + +void mach64_start_fill(mach64_t *mach64) +{ + int x, y; + + mach64->accel.dst_x = 0; + mach64->accel.dst_y = 0; + mach64->accel.dst_x_start = (mach64->dst_y_x >> 16) & 0xfff; + mach64->accel.dst_y_start = mach64->dst_y_x & 0xfff; + + mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff; + mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; + mach64->accel.x_count = mach64->accel.dst_width; + + mach64->accel.src_x = 0; + mach64->accel.src_y = 0; + mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_y_start = mach64->src_y_x & 0xfff; + if (mach64->src_cntl & SRC_LINEAR_EN) + mach64->accel.src_x_count = 0x7ffffff; /*Essentially infinite*/ + else + mach64->accel.src_x_count = (mach64->src_height1_width1 >> 16) & 0x7fff; + if (!(mach64->src_cntl & SRC_PATT_EN)) + mach64->accel.src_y_count = 0x7ffffff; /*Essentially infinite*/ + else + mach64->accel.src_y_count = mach64->src_height1_width1 & 0x1fff; + + mach64->accel.src_width1 = (mach64->src_height1_width1 >> 16) & 0x7fff; + mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; + mach64->accel.src_width2 = (mach64->src_height2_width2 >> 16) & 0x7fff; + mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; + +#ifdef MACH64_DEBUG + pclog("src %i %i %i %i %08X %08X\n", mach64->accel.src_x_count, + mach64->accel.src_y_count, + mach64->accel.src_width1, + mach64->accel.src_height1, + mach64->src_height1_width1, + mach64->src_height2_width2); +#endif + + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + + mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; + mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; + + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; + mach64->accel.mix_bg = mach64->dp_mix & 0x1f; + + mach64->accel.source_bg = mach64->dp_src & 7; + mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; + mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; + mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; + + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; + mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; + mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; + +/* mach64->accel.src_x *= mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.dst_x *= mach64_inc[mach64->accel.dst_pix_width]; + mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ + + if (mach64->accel.src_size == WIDTH_1BIT) + mach64->accel.src_offset <<= 3; + else + mach64->accel.src_offset >>= mach64->accel.src_size; + + if (mach64->accel.dst_size == WIDTH_1BIT) + mach64->accel.dst_offset <<= 3; + else + mach64->accel.dst_offset >>= mach64->accel.dst_size; + +/* if (mach64->accel.source_fg == SRC_BLITSRC || mach64->accel.source_bg == SRC_BLITSRC) + {*/ + mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; +/* } + else + { + mach64->accel.xinc = mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.yinc = 1; + }*/ + + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); + + +// pclog("mach64_start_fill : pattern %08X %08X\n", mach64->pat_reg0, mach64->pat_reg1); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; + mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; +// pclog("%i ", mach64->accel.pattern[y][x]); + } +// pclog("\n"); + } + + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; + mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; + mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; + mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; + +/* mach64->accel.sc_left *= mach64_inc[mach64->accel.dst_pix_width]; + mach64->accel.sc_right *= mach64_inc[mach64->accel.dst_pix_width];*/ + + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; + mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; + mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; + mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); + + mach64->accel.poly_draw = 0; + + mach64->accel.busy = 1; +#ifdef MACH64_DEBUG + pclog("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg); +#endif + mach64->accel.op = OP_RECT; +} + +void mach64_start_line(mach64_t *mach64) +{ + int x, y; + + mach64->accel.dst_x = (mach64->dst_y_x >> 16) & 0xfff; + mach64->accel.dst_y = mach64->dst_y_x & 0xfff; + + mach64->accel.src_x = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_y = mach64->src_y_x & 0xfff; + + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + + mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; + mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; + + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; + mach64->accel.mix_bg = mach64->dp_mix & 0x1f; + + mach64->accel.source_bg = mach64->dp_src & 7; + mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; + mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; + mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; + + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; + mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; + mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; + + if (mach64->accel.src_size == WIDTH_1BIT) + mach64->accel.src_offset <<= 3; + else + mach64->accel.src_offset >>= mach64->accel.src_size; + + if (mach64->accel.dst_size == WIDTH_1BIT) + mach64->accel.dst_offset <<= 3; + else + mach64->accel.dst_offset >>= mach64->accel.dst_size; + +/* mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ + + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); + + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; + mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; + } + } + + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; + mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; + mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; + mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; + + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + + mach64->accel.x_count = mach64->dst_bres_lnth & 0x7fff; + mach64->accel.err = (mach64->dst_bres_err & 0x3ffff) | ((mach64->dst_bres_err & 0x40000) ? 0xfffc0000 : 0); + + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; + mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; + mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; + mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); + + mach64->accel.busy = 1; +#ifdef MACH64_DEBUG + pclog("mach64_start_line\n"); +#endif + mach64->accel.op = OP_LINE; +} + +#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ + else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ + else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ + else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; + +#define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = 0xffffffff; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } + +#define WRITE(addr, width) if (width == 0) \ + { \ + svga->vram[(addr) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[((addr) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else if (width == 1) \ + { \ + *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 1) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else if (width == 2) \ + { \ + *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 2) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else \ + { \ + if (dest_dat & 1) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) & 7); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) & 7)); \ + svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = changeframecount; \ + } + +void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + int cmp_clr = 0; + + if (!mach64->accel.busy) + { +#ifdef MACH64_DEBUG + pclog("mach64_blit : return as not busy\n"); +#endif + return; + } + switch (mach64->accel.op) + { + case OP_RECT: + while (count) + { + uint32_t src_dat, dest_dat; + uint32_t host_dat; + int mix; + int dst_x = (mach64->accel.dst_x + mach64->accel.dst_x_start) & 0xfff; + int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff; + int src_x; + int src_y = (mach64->accel.src_y + mach64->accel.src_y_start) & 0xfff; + + if (mach64->src_cntl & SRC_LINEAR_EN) + src_x = mach64->accel.src_x; + else + src_x = (mach64->accel.src_x + mach64->accel.src_x_start) & 0xfff; + + if (mach64->accel.source_host) + { + host_dat = cpu_dat; + switch (mach64->accel.host_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64->accel.source_mix) + { + case MONO_SRC_HOST: + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) + { + mix = cpu_dat & 1; + cpu_dat >>= 1; + } + else + { + mix = cpu_dat >> 31; + cpu_dat <<= 1; + } + break; + case MONO_SRC_PAT: + mix = mach64->accel.pattern[dst_y & 7][dst_x & 7]; + break; + case MONO_SRC_1: + mix = 1; + break; + case MONO_SRC_BLITSRC: + if (mach64->src_cntl & SRC_LINEAR_EN) + { + READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); + } + else + { + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); + } + break; + } + + if (dst_x >= mach64->accel.sc_left && dst_x <= mach64->accel.sc_right && + dst_y >= mach64->accel.sc_top && dst_y <= mach64->accel.sc_bottom) + { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + if (mach64->dst_cntl & DST_POLYGON_EN) + { + int poly_src; + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, poly_src, mach64->accel.src_size); + if (poly_src) + mach64->accel.poly_draw = !mach64->accel.poly_draw; + } + if (!(mach64->dst_cntl & DST_POLYGON_EN) || mach64->accel.poly_draw) + { + READ(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, dest_dat, mach64->accel.dst_size); + + switch (mach64->accel.clr_cmp_fn) + { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + + WRITE(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, mach64->accel.dst_size); + } + } + + if (mach64->dst_cntl & DST_24_ROT_EN) + { + mach64->accel.dp_frgd_clr = ((mach64->accel.dp_frgd_clr >> 8) & 0xffff) | (mach64->accel.dp_frgd_clr << 16); + mach64->accel.dp_bkgd_clr = ((mach64->accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64->accel.dp_bkgd_clr << 16); + } + + mach64->accel.src_x += mach64->accel.xinc; + mach64->accel.dst_x += mach64->accel.xinc; + if (!(mach64->src_cntl & SRC_LINEAR_EN)) + { + mach64->accel.src_x_count--; + if (mach64->accel.src_x_count <= 0) + { + mach64->accel.src_x = 0; + if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN)) + { + mach64->accel.src_x_start = (mach64->src_y_x_start >> 16) & 0xfff; + mach64->accel.src_x_count = mach64->accel.src_width2; + } + else + mach64->accel.src_x_count = mach64->accel.src_width1; + } + } + + mach64->accel.x_count--; + + if (mach64->accel.x_count <= 0) + { + mach64->accel.x_count = mach64->accel.dst_width; + mach64->accel.dst_x = 0; + mach64->accel.dst_y += mach64->accel.yinc; + mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_x_count = mach64->accel.src_width1; + + if (!(mach64->src_cntl & SRC_LINEAR_EN)) + { + mach64->accel.src_x = 0; + mach64->accel.src_y += mach64->accel.yinc; + mach64->accel.src_y_count--; + if (mach64->accel.src_y_count <= 0) + { + mach64->accel.src_y = 0; + if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN)) + { + mach64->accel.src_y_start = mach64->src_y_x_start & 0xfff; + mach64->accel.src_y_count = mach64->accel.src_height2; + } + else + mach64->accel.src_y_count = mach64->accel.src_height1; + } + } + + mach64->accel.poly_draw = 0; + + mach64->accel.dst_height--; + + if (mach64->accel.dst_height <= 0) + { + /*Blit finished*/ +#ifdef MACH64_DEBUG + pclog("mach64 blit finished\n"); +#endif + mach64->accel.busy = 0; + if (mach64->dst_cntl & DST_X_TILE) + mach64->dst_y_x = (mach64->dst_y_x & 0xfff) | ((mach64->dst_y_x + (mach64->accel.dst_width << 16)) & 0xfff0000); + if (mach64->dst_cntl & DST_Y_TILE) + mach64->dst_y_x = (mach64->dst_y_x & 0xfff0000) | ((mach64->dst_y_x + (mach64->dst_height_width & 0x1fff)) & 0xfff); + return; + } + if (mach64->accel.source_host) + return; + } + } + break; + + case OP_LINE: + while (count) + { + uint32_t src_dat, dest_dat; + uint32_t host_dat; + int mix; + int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN); + + if (mach64->accel.source_host) + { + host_dat = cpu_dat; + switch (mach64->accel.src_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64->accel.source_mix) + { + case MONO_SRC_HOST: + mix = cpu_dat >> 31; + cpu_dat <<= 1; + break; + case MONO_SRC_PAT: + mix = mach64->accel.pattern[mach64->accel.dst_y & 7][mach64->accel.dst_x & 7]; + break; + case MONO_SRC_1: + default: + mix = 1; + break; + } + + if (mach64->dst_cntl & DST_POLYGON_EN) + { + if (mach64->dst_cntl & DST_Y_MAJOR) + draw_pixel = 1; + else if ((mach64->dst_cntl & DST_X_DIR) && mach64->accel.err < (mach64->dst_bres_dec + mach64->dst_bres_inc)) /*X+*/ + draw_pixel = 1; + else if (!(mach64->dst_cntl & DST_X_DIR) && mach64->accel.err >= 0) /*X-*/ + draw_pixel = 1; + } + + if (mach64->accel.x_count == 1 && !(mach64->dst_cntl & DST_LAST_PEL)) + draw_pixel = 0; + + if (mach64->accel.dst_x >= mach64->accel.sc_left && mach64->accel.dst_x <= mach64->accel.sc_right && + mach64->accel.dst_y >= mach64->accel.sc_top && mach64->accel.dst_y <= mach64->accel.sc_bottom && draw_pixel) + { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + + READ(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, dest_dat, mach64->accel.dst_size); + +// pclog("Blit %i,%i %i,%i %X %X %i %02X %02X %i ", mach64->accel.src_x, mach64->accel.src_y, mach64->accel.dst_x, mach64->accel.dst_y, (mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x) & 0x7fffff, (mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x) & 0x7fffff, count, src_dat, dest_dat, mix); + + switch (mach64->accel.clr_cmp_fn) + { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + +// pclog("%02X %i\n", dest_dat, mach64->accel.dst_height); + + WRITE(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, mach64->accel.dst_size); + } + + mach64->accel.x_count--; + if (mach64->accel.x_count <= 0) + { + /*Blit finished*/ +#ifdef MACH64_DEBUG + pclog("mach64 blit finished\n"); +#endif + mach64->accel.busy = 0; + return; + } + + switch (mach64->dst_cntl & 7) + { + case 0: case 2: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 1: case 3: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + case 4: case 5: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 6: case 7: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + } +#ifdef MACH64_DEBUG + pclog("x %i y %i err %i inc %i dec %i\n", mach64->accel.dst_x, mach64->accel.dst_y, mach64->accel.err, mach64->dst_bres_inc, mach64->dst_bres_dec); +#endif + if (mach64->accel.err >= 0) + { + mach64->accel.err += mach64->dst_bres_dec; + + switch (mach64->dst_cntl & 7) + { + case 0: case 1: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 2: case 3: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + case 4: case 6: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 5: case 7: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + } + } + else + mach64->accel.err += mach64->dst_bres_inc; + } + break; + } +} + +void mach64_load_context(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + uint32_t addr; + + while (mach64->context_load_cntl & 0x30000) + { + addr = ((0x3fff - (mach64->context_load_cntl & 0x3fff)) * 256) & mach64->vram_mask; + mach64->context_mask = *(uint32_t *)&svga->vram[addr]; +#ifdef MACH64_DEBUG + pclog("mach64_load_context %08X from %08X : mask %08X\n", mach64->context_load_cntl, addr, mach64->context_mask); +#endif + + if (mach64->context_mask & (1 << 2)) + mach64_accel_write_fifo_l(mach64, 0x100, *(uint32_t *)&svga->vram[addr + 0x08]); + if (mach64->context_mask & (1 << 3)) + mach64_accel_write_fifo_l(mach64, 0x10c, *(uint32_t *)&svga->vram[addr + 0x0c]); + if (mach64->context_mask & (1 << 4)) + mach64_accel_write_fifo_l(mach64, 0x118, *(uint32_t *)&svga->vram[addr + 0x10]); + if (mach64->context_mask & (1 << 5)) + mach64_accel_write_fifo_l(mach64, 0x124, *(uint32_t *)&svga->vram[addr + 0x14]); + if (mach64->context_mask & (1 << 6)) + mach64_accel_write_fifo_l(mach64, 0x128, *(uint32_t *)&svga->vram[addr + 0x18]); + if (mach64->context_mask & (1 << 7)) + mach64_accel_write_fifo_l(mach64, 0x12c, *(uint32_t *)&svga->vram[addr + 0x1c]); + if (mach64->context_mask & (1 << 8)) + mach64_accel_write_fifo_l(mach64, 0x180, *(uint32_t *)&svga->vram[addr + 0x20]); + if (mach64->context_mask & (1 << 9)) + mach64_accel_write_fifo_l(mach64, 0x18c, *(uint32_t *)&svga->vram[addr + 0x24]); + if (mach64->context_mask & (1 << 10)) + mach64_accel_write_fifo_l(mach64, 0x198, *(uint32_t *)&svga->vram[addr + 0x28]); + if (mach64->context_mask & (1 << 11)) + mach64_accel_write_fifo_l(mach64, 0x1a4, *(uint32_t *)&svga->vram[addr + 0x2c]); + if (mach64->context_mask & (1 << 12)) + mach64_accel_write_fifo_l(mach64, 0x1b0, *(uint32_t *)&svga->vram[addr + 0x30]); + if (mach64->context_mask & (1 << 13)) + mach64_accel_write_fifo_l(mach64, 0x280, *(uint32_t *)&svga->vram[addr + 0x34]); + if (mach64->context_mask & (1 << 14)) + mach64_accel_write_fifo_l(mach64, 0x284, *(uint32_t *)&svga->vram[addr + 0x38]); + if (mach64->context_mask & (1 << 15)) + mach64_accel_write_fifo_l(mach64, 0x2a8, *(uint32_t *)&svga->vram[addr + 0x3c]); + if (mach64->context_mask & (1 << 16)) + mach64_accel_write_fifo_l(mach64, 0x2b4, *(uint32_t *)&svga->vram[addr + 0x40]); + if (mach64->context_mask & (1 << 17)) + mach64_accel_write_fifo_l(mach64, 0x2c0, *(uint32_t *)&svga->vram[addr + 0x44]); + if (mach64->context_mask & (1 << 18)) + mach64_accel_write_fifo_l(mach64, 0x2c4, *(uint32_t *)&svga->vram[addr + 0x48]); + if (mach64->context_mask & (1 << 19)) + mach64_accel_write_fifo_l(mach64, 0x2c8, *(uint32_t *)&svga->vram[addr + 0x4c]); + if (mach64->context_mask & (1 << 20)) + mach64_accel_write_fifo_l(mach64, 0x2cc, *(uint32_t *)&svga->vram[addr + 0x50]); + if (mach64->context_mask & (1 << 21)) + mach64_accel_write_fifo_l(mach64, 0x2d0, *(uint32_t *)&svga->vram[addr + 0x54]); + if (mach64->context_mask & (1 << 22)) + mach64_accel_write_fifo_l(mach64, 0x2d4, *(uint32_t *)&svga->vram[addr + 0x58]); + if (mach64->context_mask & (1 << 23)) + mach64_accel_write_fifo_l(mach64, 0x2d8, *(uint32_t *)&svga->vram[addr + 0x5c]); + if (mach64->context_mask & (1 << 24)) + mach64_accel_write_fifo_l(mach64, 0x300, *(uint32_t *)&svga->vram[addr + 0x60]); + if (mach64->context_mask & (1 << 25)) + mach64_accel_write_fifo_l(mach64, 0x304, *(uint32_t *)&svga->vram[addr + 0x64]); + if (mach64->context_mask & (1 << 26)) + mach64_accel_write_fifo_l(mach64, 0x308, *(uint32_t *)&svga->vram[addr + 0x68]); + if (mach64->context_mask & (1 << 27)) + mach64_accel_write_fifo_l(mach64, 0x330, *(uint32_t *)&svga->vram[addr + 0x6c]); + + mach64->context_load_cntl = *(uint32_t *)&svga->vram[addr + 0x70]; + } +} + +uint8_t mach64_ext_readb(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + READ8(addr, mach64->crtc_h_total_disp); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + READ8(addr, mach64->crtc_v_total_disp); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + READ8(addr, mach64->crtc_v_sync_strt_wid); + break; + + case 0x12: case 0x13: + READ8(addr - 2, mach64->svga.vc); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + READ8(addr, mach64->crtc_off_pitch); + break; + + case 0x18: + ret = mach64->crtc_int_cntl & ~1; + if (mach64->svga.cgastat & 8) + ret |= 1; + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + READ8(addr, mach64->crtc_gen_cntl); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + READ8(addr, mach64->ovr_clr); + break; + case 0x44: case 0x45: case 0x46: case 0x47: + READ8(addr, mach64->ovr_wid_left_right); + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: + READ8(addr, mach64->ovr_wid_top_bottom); + break; + + case 0x68: case 0x69: case 0x6a: case 0x6b: + READ8(addr, mach64->cur_offset); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + READ8(addr, mach64->cur_horz_vert_posn); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + READ8(addr, mach64->cur_horz_vert_off); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + READ8(addr, mach64->scratch_reg0); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + READ8(addr, mach64->scratch_reg1); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + READ8(addr, mach64->clock_cntl); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + READ8(addr, mach64->mem_cntl); + break; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + break; + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + READ8(addr, mach64->dac_cntl); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + READ8(addr, mach64->gen_test_cntl); + break; + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + READ8(addr, 0x020000d7); /*88800GX-2*/ + break; + + case 0x100: case 0x101: case 0x102: case 0x103: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_off_pitch); + break; + case 0x104: case 0x105: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_y_x); + break; + case 0x108: case 0x109: case 0x11c: case 0x11d: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->dst_y_x); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_y_x); + break; + case 0x110: case 0x111: + addr += 2; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_height_width); + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_lnth); + break; + case 0x124: case 0x125: case 0x126: case 0x127: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_err); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_inc); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_dec); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_cntl); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_off_pitch); + break; + case 0x184: case 0x185: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x); + break; + case 0x188: case 0x189: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_y_x); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x); + break; + case 0x190: case 0x191: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_height1_width1); + break; + case 0x194: case 0x195: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height1_width1); + break; + case 0x198: case 0x199: case 0x19a: case 0x19b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height1_width1); + break; + case 0x19c: case 0x19d: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x_start); + break; + case 0x1a0: case 0x1a1: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_y_x_start); + break; + case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x_start); + break; + case 0x1a8: case 0x1a9: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_height2_width2); + break; + case 0x1ac: case 0x1ad: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height2_width2); + break; + case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height2_width2); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_cntl); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->pat_reg0); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->pat_reg1); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_left_right); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_left_right); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_top_bottom); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_top_bottom); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_bkgd_clr); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_frgd_clr); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_pix_width); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_mix); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_src); + break; + + case 0x300: case 0x301: case 0x302: case 0x303: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_clr); + break; + case 0x304: case 0x305: case 0x306: case 0x307: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_mask); + break; + case 0x308: case 0x309: case 0x30a: case 0x30b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_cntl); + break; + + case 0x310: case 0x311: + if (!FIFO_EMPTY) + wake_fifo_thread(mach64); + ret = 0; + if (FIFO_FULL) + ret = 0xff; + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->context_mask); + break; + + case 0x330: case 0x331: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_cntl); + break; + case 0x332: + mach64_wait_fifo_idle(mach64); + READ8(addr - 2, mach64->src_cntl); + break; + case 0x333: + mach64_wait_fifo_idle(mach64); + READ8(addr - 3, mach64->pat_cntl); + break; + + case 0x338: +/* if (!FIFO_EMPTY) + wake_fifo_thread(mach64);*/ + ret = FIFO_EMPTY ? 0 : 1; + break; + + default: + ret = 0; + break; + } +#ifdef MACH64_DEBUG + if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readb : addr %08X ret %02X\n", addr, ret); +#endif + return ret; +} +uint16_t mach64_ext_readw(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint16_t ret; + switch (addr & 0x3ff) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_readb(addr, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= mach64_ext_readb(addr + 1, p) << 8; + break; + } +#ifdef MACH64_DEBUG + if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readw : addr %08X ret %04X\n", addr, ret); +#endif + return ret; +} +uint32_t mach64_ext_readl(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint32_t ret; + switch (addr & 0x3ff) + { + case 0x18: + ret = mach64->crtc_int_cntl & ~1; + if (mach64->svga.cgastat & 8) + ret |= 1; + break; + + case 0xb4: + ret = (mach64->bank_w[0] >> 15) | ((mach64->bank_w[1] >> 15) << 16); + break; + case 0xb8: + ret = (mach64->bank_r[0] >> 15) | ((mach64->bank_r[1] >> 15) << 16); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_readw(addr, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= mach64_ext_readw(addr + 2, p) << 16; + break; + } +#ifdef MACH64_DEBUG + if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readl : addr %08X ret %08X\n", addr, ret); +#endif + return ret; +} + +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; +#ifdef MACH64_DEBUG + pclog("mach64_ext_writeb : addr %08X val %02X\n", addr, val); +#endif + if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3ff, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + WRITE8(addr, mach64->crtc_h_total_disp, val); + svga_recalctimings(&mach64->svga); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + WRITE8(addr, mach64->crtc_v_total_disp, val); + svga_recalctimings(&mach64->svga); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + WRITE8(addr, mach64->crtc_v_sync_strt_wid, val); + svga_recalctimings(&mach64->svga); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + WRITE8(addr, mach64->crtc_off_pitch, val); + svga_recalctimings(&mach64->svga); + svga->fullchange = changeframecount; + break; + + case 0x18: + mach64->crtc_int_cntl = val; + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + WRITE8(addr, mach64->crtc_gen_cntl, val); + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + svga->fb_only = 1; + else + svga->fb_only = 0; + svga_recalctimings(&mach64->svga); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + WRITE8(addr, mach64->ovr_clr, val); + break; + case 0x44: case 0x45: case 0x46: case 0x47: + WRITE8(addr, mach64->ovr_wid_left_right, val); + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: + WRITE8(addr, mach64->ovr_wid_top_bottom, val); + break; + + case 0x68: case 0x69: case 0x6a: case 0x6b: + WRITE8(addr, mach64->cur_offset, val); + svga->hwcursor.addr = (mach64->cur_offset & 0xfffff) * 8; + mach64_cursor_dump(mach64); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + WRITE8(addr, mach64->cur_horz_vert_posn, val); + svga->hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff; + svga->hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff; + mach64_cursor_dump(mach64); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + WRITE8(addr, mach64->cur_horz_vert_off, val); + svga->hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f; + svga->hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f; + mach64_cursor_dump(mach64); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + WRITE8(addr, mach64->scratch_reg0, val); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + WRITE8(addr, mach64->scratch_reg1, val); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + WRITE8(addr, mach64->clock_cntl, val); + ics2595_write(&mach64->ics2595, val & 0x40, val & 0xf); + svga_recalctimings(&mach64->svga); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + WRITE8(addr, mach64->mem_cntl, val); + break; + + case 0xb4: + mach64->bank_w[0] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : write bank A0000-A7FFF set to %08X\n", mach64->bank_w[0]); +#endif + break; + case 0xb5: case 0xb6: + mach64->bank_w[1] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : write bank A8000-AFFFF set to %08X\n", mach64->bank_w[1]); +#endif + break; + case 0xb8: + mach64->bank_r[0] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : read bank A0000-A7FFF set to %08X\n", mach64->bank_r[0]); +#endif + break; + case 0xb9: case 0xba: + mach64->bank_r[1] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : read bank A8000-AFFFF set to %08X\n", mach64->bank_r[1]); +#endif + break; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + break; + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + WRITE8(addr, mach64->dac_cntl, val); + svga_set_ramdac_type(svga, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + ati68860_set_ramdac_type(&mach64->ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + WRITE8(addr, mach64->gen_test_cntl, val); +// if (val == 2) output = 3; + ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1); + mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0); + svga->hwcursor.ena = mach64->gen_test_cntl & 0x80; + mach64_cursor_dump(mach64); + break; + } +} +void mach64_ext_writew(uint32_t addr, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; +#ifdef MACH64_DEBUG + pclog("mach64_ext_writew : addr %08X val %04X\n", addr, val); +#endif + if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3fe, val, FIFO_WRITE_WORD); + } + else switch (addr & 0x3fe) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writeb(addr, val, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writeb(addr + 1, val >> 8, p); + break; + } +} +void mach64_ext_writel(uint32_t addr, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; +#ifdef MACH64_DEBUG + if ((addr & 0x3c0) != 0x200) + pclog("mach64_ext_writel : addr %08X val %08X\n", addr, val); +#endif + if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3fc, val, FIFO_WRITE_DWORD); + } + else switch (addr & 0x3fc) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writew(addr, val, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writew(addr + 2, val >> 16, p); + break; + } +} + +uint8_t mach64_ext_inb(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; +// if (CS == 0x2be7) output = 3; + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: + ret = mach64_ext_readb(0x00 | (port & 3), p); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + ret = mach64_ext_readb(0x08 | (port & 3), p); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + ret = mach64_ext_readb(0x0c | (port & 3), p); + break; + + case 0x12ec: case 0x12ed: case 0x12ee: case 0x12ef: + ret = mach64_ext_readb(0x10 | (port & 3), p); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + ret = mach64_ext_readb(0x14 | (port & 3), p); + break; + + case 0x1aec: + ret = mach64_ext_readb(0x18, p); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + ret = mach64_ext_readb(0x1c | (port & 3), p); + break; + + case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: + ret = mach64_ext_readb(0x40 | (port & 3), p); + break; + case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: + ret = mach64_ext_readb(0x44 | (port & 3), p); + break; + case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: + ret = mach64_ext_readb(0x48 | (port & 3), p); + break; + + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + ret = mach64_ext_readb(0x68 | (port & 3), p); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + ret = mach64_ext_readb(0x6c | (port & 3), p); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + ret = mach64_ext_readb(0x70 | (port & 3), p); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + ret = mach64_ext_readb(0x80 | (port & 3), p); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + ret = mach64_ext_readb(0x84 | (port & 3), p); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + ret = mach64_ext_readb(0x90 | (port & 3), p); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + ret = mach64_ext_readb(0xb0 | (port & 3), p); + break; + + case 0x56ec: + ret = mach64_ext_readb(0xb4, p); + break; + case 0x56ed: case 0x56ee: + ret = mach64_ext_readb(0xb5, p); + break; + case 0x5aec: + ret = mach64_ext_readb(0xb8, p); + break; + case 0x5aed: case 0x5aee: + ret = mach64_ext_readb(0xb9, p); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + ret = mach64_ext_readb(0xc4 | (port & 3), p); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + ret = mach64_ext_readb(0xd0 | (port & 3), p); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4); + READ8(port, mach64->config_cntl); + break; + + case 0x6eec: case 0x6eed: case 0x6eee: case 0x6eef: + ret = mach64_ext_readb(0xe0 | (port & 3), p); + break; + + case 0x72ec: + if (PCI) + ret = 7 | (3 << 3); /*PCI, 256Kx16 DRAM*/ + else + ret = 6 | (3 << 3); /*VLB, 256Kx16 DRAM*/ + break; + case 0x72ed: + ret = 5 << 1; /*ATI-68860*/ + break; + + default: + ret = 0; + break; + } +#ifdef MACH64_DEBUG + pclog("mach64_ext_inb : port %04X ret %02X %04X:%04X\n", port, ret, CS,cpu_state.pc); +#endif + return ret; +} +uint16_t mach64_ext_inw(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint16_t ret; + switch (port) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_inb(port, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= (mach64_ext_inb(port + 1, p) << 8); + break; + } +#ifdef MACH64_DEBUG + pclog("mach64_ext_inw : port %04X ret %04X\n", port, ret); +#endif + return ret; +} +uint32_t mach64_ext_inl(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint32_t ret; + switch (port) + { + case 0x56ec: + ret = mach64_ext_readl(0xb4, p); + break; + case 0x5aec: + ret = mach64_ext_readl(0xb8, p); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_inw(port, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= (mach64_ext_inw(port + 2, p) << 16); + break; + } +#ifdef MACH64_DEBUG + pclog("mach64_ext_inl : port %04X ret %08X\n", port, ret); +#endif + return ret; +} + +void mach64_ext_outb(uint16_t port, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; +#ifdef MACH64_DEBUG + pclog("mach64_ext_outb : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); +#endif + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: + mach64_ext_writeb(0x00 | (port & 3), val, p); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + mach64_ext_writeb(0x08 | (port & 3), val, p); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + mach64_ext_writeb(0x0c | (port & 3), val, p); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + mach64_ext_writeb(0x14 | (port & 3), val, p); + break; + + case 0x1aec: + mach64_ext_writeb(0x18, val, p); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + mach64_ext_writeb(0x1c | (port & 3), val, p); + break; + + case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: + mach64_ext_writeb(0x40 | (port & 3), val, p); + break; + case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: + mach64_ext_writeb(0x44 | (port & 3), val, p); + break; + case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: + mach64_ext_writeb(0x48 | (port & 3), val, p); + break; + + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + mach64_ext_writeb(0x68 | (port & 3), val, p); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + mach64_ext_writeb(0x6c | (port & 3), val, p); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + mach64_ext_writeb(0x70 | (port & 3), val, p); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + mach64_ext_writeb(0x80 | (port & 3), val, p); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + mach64_ext_writeb(0x84 | (port & 3), val, p); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + mach64_ext_writeb(0x90 | (port & 3), val, p); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + mach64_ext_writeb(0xb0 | (port & 3), val, p); + break; + + case 0x56ec: + mach64_ext_writeb(0xb4, val, p); + break; + case 0x56ed: case 0x56ee: + mach64_ext_writeb(0xb5, val, p); + break; + case 0x5aec: + mach64_ext_writeb(0xb8, val, p); + break; + case 0x5aed: case 0x5aee: + mach64_ext_writeb(0xb9, val, p); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + mach64_ext_writeb(0xc4 | (port & 3), val, p); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + mach64_ext_writeb(0xd0 | (port & 3), val, p); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + WRITE8(port, mach64->config_cntl, val); + mach64_updatemapping(mach64); + break; + } +} +void mach64_ext_outw(uint16_t port, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; +#ifdef MACH64_DEBUG + pclog("mach64_ext_outw : port %04X val %04X\n", port, val); +#endif + switch (port) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outb(port, val, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outb(port + 1, val >> 8, p); + break; + } +} +void mach64_ext_outl(uint16_t port, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + pclog("mach64_ext_outl : port %04X val %08X\n", port, val); + switch (port) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outw(port, val, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outw(port + 2, val >> 16, p); + break; + } +} + +void mach64_write(uint32_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; +// pclog("mach64_write : %05X %02X ", addr, val); + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; +// pclog("%08X\n", addr); + svga_write_linear(addr, val, svga); +} + +uint8_t mach64_read(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + uint8_t ret; +// pclog("mach64_read : %05X ", addr); + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + ret = svga_read_linear(addr, svga); +// pclog("%08X %02X\n", addr, ret); + return ret; +} + +void mach64_hwcursor_draw(svga_t *svga, int displine) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int x, offset; + uint8_t dat; + uint32_t col0 = mach64->ramdac.pallook[0]; + uint32_t col1 = mach64->ramdac.pallook[1]; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + offset = svga->hwcursor_latch.xoff; + for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) + { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga->hwcursor_latch.addr += 16; +} + +static void mach64_io_remove(mach64_t *mach64) +{ + int c; + + io_removehandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + for (c = 0; c < 8; c++) + { + io_removehandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + } + + io_removehandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); +} + +static void mach64_io_set(mach64_t *mach64) +{ + int c; + + mach64_io_remove(mach64); + + io_sethandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + for (c = 0; c < 8; c++) + { + io_sethandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + } + + io_sethandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); +} + +uint8_t mach64_pci_read(int func, int addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + +// pclog("Mach64 PCI read %08X\n", addr); + + switch (addr) + { + case 0x00: return 0x02; /*ATi*/ + case 0x01: return 0x10; + + case 0x02: return 'X'; /*88800GX*/ + case 0x03: return 'G'; + + case PCI_REG_COMMAND: + return mach64->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return mach64->linear_base >> 16; + case 0x13: return mach64->linear_base >> 24; + + case 0x30: return mach64->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return mach64->pci_regs[0x32]; + case 0x33: return mach64->pci_regs[0x33]; + } + return 0; +} + +void mach64_pci_write(int func, int addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + +// pclog("Mach64 PCI write %08X %02X\n", addr, val); + + switch (addr) + { + case PCI_REG_COMMAND: + if (romset == ROM_KN97) return; + mach64->pci_regs[PCI_REG_COMMAND] = val & 0x27; + if (val & PCI_COMMAND_IO) + mach64_io_set(mach64); + else + mach64_io_remove(mach64); + mach64_updatemapping(mach64); + break; + + case 0x12: + mach64->linear_base = (mach64->linear_base & 0xff000000) | ((val & 0x80) << 16); + mach64_updatemapping(mach64); + break; + case 0x13: + mach64->linear_base = (mach64->linear_base & 0x800000) | (val << 24); + mach64_updatemapping(mach64); + break; + + case 0x30: case 0x32: case 0x33: + mach64->pci_regs[addr] = val; + if (mach64->pci_regs[0x30] & 0x01) + { + uint32_t addr = (mach64->pci_regs[0x32] << 16) | (mach64->pci_regs[0x33] << 24); + pclog("Mach64 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&mach64->bios_rom.mapping, addr, 0x8000); + } + else + { + pclog("Mach64 bios_rom disabled\n"); + mem_mapping_disable(&mach64->bios_rom.mapping); + } + return; + } +} + +void *mach64gx_init() +{ + int c; + mach64_t *mach64 = malloc(sizeof(mach64_t)); + memset(mach64, 0, sizeof(mach64_t)); + + mach64->vram_size = device_get_config_int("memory"); + mach64->vram_mask = (mach64->vram_size << 20) - 1; + + svga_init(&mach64->svga, mach64, mach64->vram_size << 20, + mach64_recalctimings, + mach64_in, mach64_out, + mach64_hwcursor_draw, + NULL); + + rom_init(&mach64->bios_rom, "roms/mach64gx/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&mach64->bios_rom.mapping); + + mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &mach64->svga); + mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_disable(&mach64->mmio_mapping); + + mach64_io_set(mach64); + + pci_add(mach64_pci_read, mach64_pci_write, mach64); + + mach64->pci_regs[PCI_REG_COMMAND] = 3; + mach64->pci_regs[0x30] = 0x00; + mach64->pci_regs[0x32] = 0x0c; + mach64->pci_regs[0x33] = 0x00; + + ati_eeprom_load(&mach64->eeprom, "mach64.nvr", 1); + + ati68860_ramdac_init(&mach64->ramdac); + + mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ + + mach64->dst_cntl = 3; + + mach64->wake_fifo_thread = thread_create_event(); + mach64->fifo_not_full_event = thread_create_event(); + mach64->fifo_thread = thread_create(fifo_thread, mach64); + + return mach64; +} + +int mach64gx_available() +{ + return rom_present("roms/mach64gx/bios.bin"); +} + +void mach64_close(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + svga_close(&mach64->svga); + + free(mach64); +} + +void mach64_speed_changed(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + svga_recalctimings(&mach64->svga); +} + +void mach64_force_redraw(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64->svga.fullchange = changeframecount; +} + +void mach64_add_status_info(char *s, int max_len, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - mach64->status_time; + mach64->status_time = new_time; + + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + { + svga_t *svga = &mach64->svga; + char temps[128]; + int bpp = 4; + + strncat(s, "Mach64 in native mode\n", max_len); + + switch ((mach64->crtc_gen_cntl >> 8) & 7) + { + case 1: bpp = 4; break; + case 2: bpp = 8; break; + case 3: bpp = 15; break; + case 4: bpp = 16; break; + case 5: bpp = 24; break; + case 6: bpp = 32; break; + } + + sprintf(temps, "Mach64 colour depth : %i bpp\n", bpp); + strncat(s, temps, max_len); + + sprintf(temps, "Mach64 resolution : %i x %i\n", svga->hdisp, svga->dispend); + strncat(s, temps, max_len); + + sprintf(temps, "Mach64 refresh rate : %i Hz\n\n", svga->frames); + svga->frames = 0; + strncat(s, temps, max_len); + } + else + { + strncat(s, "Mach64 in SVGA mode\n", max_len); + svga_add_status_info(s, max_len, &mach64->svga); + } + + sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)mach64->blitter_time * 100.0) / timer_freq, ((double)mach64->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + mach64->blitter_time = 0; +} + +static device_config_t mach64gx_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +device_t mach64gx_device = +{ + "ATI Mach64GX", + 0, + mach64gx_init, + mach64_close, + mach64gx_available, + mach64_speed_changed, + mach64_force_redraw, + mach64_add_status_info, + mach64gx_config +}; diff --git a/src/vid_ati_mach64.h b/src/vid_ati_mach64.h new file mode 100644 index 000000000..95a7e9744 --- /dev/null +++ b/src/vid_ati_mach64.h @@ -0,0 +1 @@ +extern device_t mach64gx_device; diff --git a/src/vid_cga.c b/src/vid_cga.c new file mode 100644 index 000000000..7e398e1bd --- /dev/null +++ b/src/vid_cga.c @@ -0,0 +1,524 @@ +/*CGA emulation*/ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + +static int i_filt[8],q_filt[8]; + +static uint8_t tarray[65536]; + +int cga_brown; +int cga_color_burst; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void cga_recalctimings(cga_t *cga); + +void cga_out(uint16_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *)p; + uint8_t old; +// pclog("CGA_OUT %04X %02X\n", addr, val); + switch (addr) + { + case 0x3D4: + cga->crtcreg = val & 31; + return; + case 0x3D5: + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; + if (old != val) + { + if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) + { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + case 0x3D8: + if (((cga->cgamode ^ val) & 5) != 0) { + cga->cgamode = val; + update_cga16_color(cga); + } + cga->cgamode = val; + return; + case 0x3D9: + cga->cgacol = val; + return; + } +} + +uint8_t cga_in(uint16_t addr, void *p) +{ + cga_t *cga = (cga_t *)p; +// pclog("CGA_IN %04X\n", addr); + switch (addr) + { + case 0x3D4: + return cga->crtcreg; + case 0x3D5: + return cga->crtc[cga->crtcreg]; + case 0x3DA: + return cga->cgastat; + } + return 0xFF; +} + +void cga_write(uint32_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *)p; +// pclog("CGA_WRITE %04X %02X\n", addr, val); + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) { egawrites++; return; } + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) { egawrites++; return; } + cga->vram[addr & 0x3fff] = val; + cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = val; + cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + egawrites++; + cycles -= 4; +} + +uint8_t cga_read(uint32_t addr, void *p) +{ + cga_t *cga = (cga_t *)p; + cycles -= 4; + cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = cga->vram[addr & 0x3fff]; + cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = cga->vram[addr & 0x3fff]; + egareads++; +// pclog("CGA_READ %04X\n", addr); + return cga->vram[addr & 0x3fff]; +} + +void cga_recalctimings(cga_t *cga) +{ + double disptime; + double _dispontime, _dispofftime; + pclog("Recalc - %i %i %i\n", cga->crtc[0], cga->crtc[1], cga->cgamode & 1); + if (cga->cgamode & 1) + { + disptime = cga->crtc[0] + 1; + _dispontime = cga->crtc[1]; + } + else + { + disptime = (cga->crtc[0] + 1) << 1; + _dispontime = cga->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; +// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); + _dispontime *= CGACONST; + _dispofftime *= CGACONST; +// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); + cga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + cga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +void cga_poll(void *p) +{ + cga_t *cga = (cga_t *)p; + uint16_t ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + int y_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, y_val, y_tot; + int i_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, i_val, i_tot; + int q_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, q_val, q_tot; + int r, g, b; + uint8_t *tline; + if (!cga->linepos) + { + cga->vidtime += cga->dispofftime; + cga->cgastat |= 1; + cga->linepos = 1; + oldsc = cga->sc; + if ((cga->crtc[8] & 3) == 3) + cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; + if (cga->cgadispon) + { + if (cga->displine < cga->firstline) + { + cga->firstline = cga->displine; +// printf("Firstline %i\n",firstline); + } + cga->lastline = cga->displine; + for (c = 0; c < 8; c++) + { + if ((cga->cgamode & 0x12) == 0x12) + { + buffer->line[cga->displine][c] = 0; + if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = 0; + else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[cga->displine][c] = (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = (cga->cgacol & 15) + 16; + else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = (cga->cgacol & 15) + 16; + } + } + if (cga->cgamode & 1) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->charbuffer[x << 1]; + attr = cga->charbuffer[(x << 1) + 1]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + if (cga->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + cga->ma++; + } + } + else if (!(cga->cgamode & 2)) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->vram[((cga->ma << 1) & 0x3fff)]; + attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + if (cga->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80)) cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + cga->ma++; + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 4)+(c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + else if (!(cga->cgamode & 16)) + { + cols[0] = (cga->cgacol & 15) | 16; + col = (cga->cgacol & 16) ? 24 : 16; + if (cga->cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (cga->cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < cga->crtc[1]; x++) + { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = + buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + cols[0] = 0; cols[1] = (cga->cgacol & 15) + 16; + for (x = 0; x < cga->crtc[1]; x++) + { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[cga->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + cols[0] = ((cga->cgamode & 0x12) == 0x12) ? 0 : (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) hline(buffer, 0, cga->displine, (cga->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, cga->displine, (cga->crtc[1] << 4) + 16, cols[0]); + } + + if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; + else x = (cga->crtc[1] << 4) + 16; + + if (cga_comp) + { + tline = (uint8_t *) buffer32->line[cga->displine]; + + for (c = 0; c < x; c++) + { + tarray[c] = buffer->line[cga->displine][c] & 0xf; + } + + Composite_Process(cga, 0, x >> 2, tarray); + + for (c = 0; c < x; c++) + { + ((uint32_t *) tline)[c] = ((uint32_t *) tarray)[c]; + } + } + + cga->sc = oldsc; + if (cga->vc == cga->crtc[7] && !cga->sc) + cga->cgastat |= 8; + cga->displine++; + if (cga->displine >= 360) + cga->displine = 0; + } + else + { + cga->vidtime += cga->dispontime; + cga->linepos = 0; + if (cga->vsynctime) + { + cga->vsynctime--; + if (!cga->vsynctime) + cga->cgastat &= ~8; + } + if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) + { + cga->con = 0; + cga->coff = 1; + } + if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) + cga->maback = cga->ma; + if (cga->vadj) + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + cga->vadj--; + if (!cga->vadj) + { + cga->cgadispon = 1; + cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + cga->sc = 0; + } + } + else if (cga->sc == cga->crtc[9]) + { + cga->maback = cga->ma; + cga->sc = 0; + oldvc = cga->vc; + cga->vc++; + cga->vc &= 127; + + if (cga->vc == cga->crtc[6]) + cga->cgadispon = 0; + + if (oldvc == cga->crtc[4]) + { + cga->vc = 0; + cga->vadj = cga->crtc[5]; + if (!cga->vadj) cga->cgadispon = 1; + if (!cga->vadj) cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + if ((cga->crtc[10] & 0x60) == 0x20) cga->cursoron = 0; + else cga->cursoron = cga->cgablink & 8; + } + + if (cga->vc == cga->crtc[7]) + { + cga->cgadispon = 0; + cga->displine = 0; + // cga->vsynctime = (cga->crtc[3] >> 4) + 1; + cga->vsynctime = 16; + if (cga->crtc[7]) + { + if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; + else x = (cga->crtc[1] << 4) + 16; + cga->lastline++; + if (x != xsize || (cga->lastline - cga->firstline) != ysize) + { + xsize = x; + ysize = cga->lastline - cga->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } + +startblit(); + if (cga_comp) + video_blit_memtoscreen(0, cga->firstline - 4, 0, (cga->lastline - cga->firstline) + 8, xsize, (cga->lastline - cga->firstline) + 8); + else + video_blit_memtoscreen_8(0, cga->firstline - 4, xsize, (cga->lastline - cga->firstline) + 8); + frames++; +endblit(); + video_res_x = xsize - 16; + video_res_y = ysize; + if (cga->cgamode & 1) + { + video_res_x /= 8; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + cga->firstline = 1000; + cga->lastline = 0; + cga->cgablink++; + cga->oddeven ^= 1; + } + } + else + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + } + if (cga->cgadispon) cga->cgastat &= ~1; + if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) + cga->con = 1; + if (cga->cgadispon && (cga->cgamode & 1)) + { + for (x = 0; x < (cga->crtc[1] << 1); x++) + cga->charbuffer[x] = cga->vram[(((cga->ma << 1) + x) & 0x3fff)]; + } + } +} + +void cga_init(cga_t *cga) +{ +} + +void *cga_standalone_init() +{ + int c; + int cga_tint = -2; + cga_t *cga = malloc(sizeof(cga_t)); + memset(cga, 0, sizeof(cga_t)); + + cga->vram = malloc(0x4000); + + cga_comp_init(cga); + timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + mem_mapping_add(&cga->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); + + for (c = 0; c < 8192; c++) + { + ((uint64_t *) tarray)[c] = 0; + } + + overscan_x = overscan_y = 16; + + return cga; +} + +void cga_close(void *p) +{ + cga_t *cga = (cga_t *)p; + + free(cga->vram); + free(cga); +} + +void cga_speed_changed(void *p) +{ + cga_t *cga = (cga_t *)p; + + cga_recalctimings(cga); +} + +device_t cga_device = +{ + "CGA (Old)", + 0, + cga_standalone_init, + cga_close, + NULL, + cga_speed_changed, + NULL, + NULL +}; + +device_t cga_new_device = +{ + "CGA (New)", + 0, + cga_standalone_init, + cga_close, + NULL, + cga_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_cga.h b/src/vid_cga.h new file mode 100644 index 000000000..534608731 --- /dev/null +++ b/src/vid_cga.h @@ -0,0 +1,41 @@ +typedef struct cga_t +{ + mem_mapping_t mapping; + + int crtcreg; + uint8_t crtc[32]; + + uint8_t cgastat; + + uint8_t cgamode, cgacol; + + int linepos, displine; + int sc, vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + uint16_t ma, maback; + int oddeven; + + int dispontime, dispofftime; + int vidtime; + + int firstline, lastline; + + int drawcursor; + + uint8_t *vram; + + uint8_t charbuffer[256]; +} cga_t; + +void cga_init(cga_t *cga); +void cga_out(uint16_t addr, uint8_t val, void *p); +uint8_t cga_in(uint16_t addr, void *p); +void cga_write(uint32_t addr, uint8_t val, void *p); +uint8_t cga_read(uint32_t addr, void *p); +void cga_recalctimings(cga_t *cga); +void cga_poll(void *p); + +extern device_t cga_new_device; +extern device_t cga_device; diff --git a/src/vid_cga_comp.c b/src/vid_cga_comp.c new file mode 100644 index 000000000..7cacbedff --- /dev/null +++ b/src/vid_cga_comp.c @@ -0,0 +1,356 @@ +/* Code borrowed from DOSBox and adapted by OBattler. + Original author: reenigne. */ + +#include +#include +#include + +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + +int CGA_Composite_Table[1024]; + +static double brightness = 0; +static double contrast = 100; +static double saturation = 100; +static double sharpness = 0; +static double hue_offset = 0; + +// New algorithm by reenigne +// Works in all CGA modes/color settings and can simulate older and newer CGA revisions + +static const double tau = 6.28318531; // == 2*pi + +static unsigned char chroma_multiplexer[256] = { + 2, 2, 2, 2, 114,174, 4, 3, 2, 1,133,135, 2,113,150, 4, + 133, 2, 1, 99, 151,152, 2, 1, 3, 2, 96,136, 151,152,151,152, + 2, 56, 62, 4, 111,250,118, 4, 0, 51,207,137, 1,171,209, 5, + 140, 50, 54,100, 133,202, 57, 4, 2, 50,153,149, 128,198,198,135, + 32, 1, 36, 81, 147,158, 1, 42, 33, 1,210,254, 34,109,169, 77, + 177, 2, 0,165, 189,154, 3, 44, 33, 0, 91,197, 178,142,144,192, + 4, 2, 61, 67, 117,151,112, 83, 4, 0,249,255, 3,107,249,117, + 147, 1, 50,162, 143,141, 52, 54, 3, 0,145,206, 124,123,192,193, + 72, 78, 2, 0, 159,208, 4, 0, 53, 58,164,159, 37,159,171, 1, + 248,117, 4, 98, 212,218, 5, 2, 54, 59, 93,121, 176,181,134,130, + 1, 61, 31, 0, 160,255, 34, 1, 1, 58,197,166, 0,177,194, 2, + 162,111, 34, 96, 205,253, 32, 1, 1, 57,123,125, 119,188,150,112, + 78, 4, 0, 75, 166,180, 20, 38, 78, 1,143,246, 42,113,156, 37, + 252, 4, 1,188, 175,129, 1, 37, 118, 4, 88,249, 202,150,145,200, + 61, 59, 60, 60, 228,252,117, 77, 60, 58,248,251, 81,212,254,107, + 198, 59, 58,169, 250,251, 81, 80, 100, 58,154,250, 251,252,252,252}; + +static double intensity[4] = { + 77.175381, 88.654656, 166.564623, 174.228438}; + +#define NEW_CGA(c,i,r,g,b) (((c)/0.72)*0.29 + ((i)/0.28)*0.32 + ((r)/0.28)*0.1 + ((g)/0.28)*0.22 + ((b)/0.28)*0.07) + +double mode_brightness; +double mode_contrast; +double mode_hue; +double min_v; +double max_v; + +double video_ri, video_rq, video_gi, video_gq, video_bi, video_bq; +int video_sharpness; +int tandy_mode_control = 0; + +static bool new_cga = 0; +static bool is_bw = 0; +static bool is_bpp1 = 0; + +static uint8_t comp_pal[256][3]; + +static Bit8u byte_clamp_other(int v) { return v < 0 ? 0 : (v > 255 ? 255 : v); } + +FILE *df; + +void update_cga16_color(cga_t *cga) { + int x; + Bit32u x2; + + if (!new_cga) { + min_v = chroma_multiplexer[0] + intensity[0]; + max_v = chroma_multiplexer[255] + intensity[3]; + } + else { + double i0 = intensity[0]; + double i3 = intensity[3]; + min_v = NEW_CGA(chroma_multiplexer[0], i0, i0, i0, i0); + max_v = NEW_CGA(chroma_multiplexer[255], i3, i3, i3, i3); + } + mode_contrast = 256/(max_v - min_v); + mode_brightness = -min_v*mode_contrast; + if ((cga->cgamode & 3) == 1) + mode_hue = 14; + else + mode_hue = 4; + + mode_contrast *= contrast * (new_cga ? 1.2 : 1)/100; // new CGA: 120% + mode_brightness += (new_cga ? brightness-10 : brightness)*5; // new CGA: -10 + double mode_saturation = (new_cga ? 4.35 : 2.9)*saturation/100; // new CGA: 150% + + for (x = 0; x < 1024; ++x) { + int phase = x & 3; + int right = (x >> 2) & 15; + int left = (x >> 6) & 15; + int rc = right; + int lc = left; + if ((cga->cgamode & 4) != 0) { + rc = (right & 8) | ((right & 7) != 0 ? 7 : 0); + lc = (left & 8) | ((left & 7) != 0 ? 7 : 0); + } + double c = + chroma_multiplexer[((lc & 7) << 5) | ((rc & 7) << 2) | phase]; + double i = intensity[(left >> 3) | ((right >> 2) & 2)]; + double v; + if (!new_cga) + v = c + i; + else { + double r = intensity[((left >> 2) & 1) | ((right >> 1) & 2)]; + double g = intensity[((left >> 1) & 1) | (right & 2)]; + double b = intensity[(left & 1) | ((right << 1) & 2)]; + v = NEW_CGA(c, i, r, g, b); + } + CGA_Composite_Table[x] = (int) (v*mode_contrast + mode_brightness); + } + + double i = CGA_Composite_Table[6*68] - CGA_Composite_Table[6*68 + 2]; + double q = CGA_Composite_Table[6*68 + 1] - CGA_Composite_Table[6*68 + 3]; + + double a = tau*(33 + 90 + hue_offset + mode_hue)/360.0; + double c = cos(a); + double s = sin(a); + double r = 256*mode_saturation/sqrt(i*i+q*q); + + double iq_adjust_i = -(i*c + q*s)*r; + double iq_adjust_q = (q*c - i*s)*r; + + static const double ri = 0.9563; + static const double rq = 0.6210; + static const double gi = -0.2721; + static const double gq = -0.6474; + static const double bi = -1.1069; + static const double bq = 1.7046; + + video_ri = (int) (ri*iq_adjust_i + rq*iq_adjust_q); + video_rq = (int) (-ri*iq_adjust_q + rq*iq_adjust_i); + video_gi = (int) (gi*iq_adjust_i + gq*iq_adjust_q); + video_gq = (int) (-gi*iq_adjust_q + gq*iq_adjust_i); + video_bi = (int) (bi*iq_adjust_i + bq*iq_adjust_q); + video_bq = (int) (-bi*iq_adjust_q + bq*iq_adjust_i); + video_sharpness = (int) (sharpness*256/100); + +#if 0 + df = fopen("CGA_Composite_Table.dmp", "wb"); + fwrite(CGA_Composite_Table, 1024, sizeof(int), df); + fclose(df); +#endif +} + +#if 0 +void configure_comp(double h, uint8_t n, uint8_t bw, uint8_t b1) +{ + hue_offset = h; + new_cga = n; + is_bw = bw; + is_bpp1 = b1; +} +#endif + +static Bit8u byte_clamp(int v) { + v >>= 13; + return v < 0 ? 0 : (v > 255 ? 255 : v); +} + +/* 2048x1536 is the maximum we can possibly support. */ +#define SCALER_MAXWIDTH 2048 + +static int temp[SCALER_MAXWIDTH + 10]={0}; +static int atemp[SCALER_MAXWIDTH + 2]={0}; +static int btemp[SCALER_MAXWIDTH + 2]={0}; + +Bit8u * Composite_Process(cga_t *cga, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine) +{ + int x; + Bit32u x2; + + int w = blocks*4; + +#define COMPOSITE_CONVERT(I, Q) do { \ + i[1] = (i[1]<<3) - ap[1]; \ + a = ap[0]; \ + b = bp[0]; \ + c = i[0]+i[0]; \ + d = i[-1]+i[1]; \ + y = ((c+d)<<8) + video_sharpness*(c-d); \ + rr = y + video_ri*(I) + video_rq*(Q); \ + gg = y + video_gi*(I) + video_gq*(Q); \ + bb = y + video_bi*(I) + video_bq*(Q); \ + ++i; \ + ++ap; \ + ++bp; \ + *srgb = (byte_clamp(rr)<<16) | (byte_clamp(gg)<<8) | byte_clamp(bb); \ + ++srgb; \ +} while (0) + +#define OUT(v) do { *o = (v); ++o; } while (0) + + // Simulate CGA composite output + int* o = temp; + Bit8u* rgbi = TempLine; + int* b = &CGA_Composite_Table[border*68]; + for (x = 0; x < 4; ++x) + OUT(b[(x+3)&3]); + OUT(CGA_Composite_Table[(border<<6) | ((*rgbi)<<2) | 3]); + for (x = 0; x < w-1; ++x) { + OUT(CGA_Composite_Table[(rgbi[0]<<6) | (rgbi[1]<<2) | (x&3)]); + ++rgbi; + } + OUT(CGA_Composite_Table[((*rgbi)<<6) | (border<<2) | 3]); + for (x = 0; x < 5; ++x) + OUT(b[x&3]); + + if ((cga->cgamode & 4) != 0 || !cga_color_burst) { + // Decode + int* i = temp + 5; + Bit32u* srgb = (Bit32u *)TempLine; + for (x2 = 0; x2 < blocks*4; ++x2) { + int c = (i[0]+i[0])<<3; + int d = (i[-1]+i[1])<<3; + int y = ((c+d)<<8) + video_sharpness*(c-d); + ++i; + *srgb = byte_clamp(y)*0x10101; + ++srgb; + } + } + else { + // Store chroma + int* i = temp + 4; + int* ap = atemp + 1; + int* bp = btemp + 1; + for (x = -1; x < w + 1; ++x) { + ap[x] = i[-4]-((i[-2]-i[0]+i[2])<<1)+i[4]; + bp[x] = (i[-3]-i[-1]+i[1]-i[3])<<1; + ++i; + } + + // Decode + i = temp + 5; + i[-1] = (i[-1]<<3) - ap[-1]; + i[0] = (i[0]<<3) - ap[0]; + Bit32u* srgb = (Bit32u *)TempLine; + for (x2 = 0; x2 < blocks; ++x2) { + int y,a,b,c,d,rr,gg,bb; + COMPOSITE_CONVERT(a, b); + COMPOSITE_CONVERT(-b, a); + COMPOSITE_CONVERT(-a, -b); + COMPOSITE_CONVERT(b, -a); + } + } +#undef COMPOSITE_CONVERT +#undef OUT + +#if 0 + df = fopen("temp.dmp", "ab"); + fwrite(temp, SCALER_MAXWIDTH + 10, sizeof(int), df); + fclose(df); + df = fopen("atemp.dmp", "ab"); + fwrite(atemp, SCALER_MAXWIDTH + 2, sizeof(int), df); + fclose(df); + df = fopen("btemp.dmp", "ab"); + fwrite(btemp, SCALER_MAXWIDTH + 2, sizeof(int), df); + fclose(df); +#endif + + return TempLine; +} + +void IncreaseHue(cga_t *cga) +{ + hue_offset += 5.0; + + update_cga16_color(cga); +} + +void DecreaseHue(cga_t *cga) +{ + hue_offset -= 5.0; + + update_cga16_color(cga); +} + +void IncreaseSaturation(cga_t *cga) +{ + saturation += 5; + + update_cga16_color(cga); +} + +void DecreaseSaturation(cga_t *cga) +{ + saturation -= 5; + + update_cga16_color(cga); +} + +void IncreaseContrast(cga_t *cga) +{ + contrast += 5; + + update_cga16_color(cga); +} + +void DecreaseContrast(cga_t *cga) +{ + contrast -= 5; + + update_cga16_color(cga); +} + +void IncreaseBrightness(cga_t *cga) +{ + brightness += 5; + + update_cga16_color(cga); +} + +void DecreaseBrightness(cga_t *cga) +{ + brightness -= 5; + + update_cga16_color(cga); +} + +void IncreaseSharpness(cga_t *cga) +{ + sharpness += 10; + + update_cga16_color(cga); +} + +void DecreaseSharpness(cga_t *cga) +{ + sharpness -= 10; + + update_cga16_color(cga); +} + +void cga_comp_init(cga_t *cga) +{ + new_cga = (gfxcard == GFX_NEW_CGA); + + /* Making sure this gets reset after reset. */ + brightness = 0; + contrast = 100; + saturation = 100; + sharpness = 0; + hue_offset = 0; + + update_cga16_color(cga); +} \ No newline at end of file diff --git a/src/vid_cga_comp.h b/src/vid_cga_comp.h new file mode 100644 index 000000000..809257bf2 --- /dev/null +++ b/src/vid_cga_comp.h @@ -0,0 +1,8 @@ +#define Bit8u uint8_t +#define Bit32u uint32_t +#define Bitu unsigned int +#define bool uint8_t + +void update_cga16_color(cga_t *cga); +void cga_comp_init(cga_t *cga); +Bit8u * Composite_Process(cga_t *cga, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine); diff --git a/src/vid_cl5429.c b/src/vid_cl5429.c new file mode 100644 index 000000000..bca9d3d7b --- /dev/null +++ b/src/vid_cl5429.c @@ -0,0 +1,915 @@ +/*Cirrus Logic CL-GD5429 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_cl5429.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_unk_ramdac.h" + +typedef struct gd5429_t +{ + mem_mapping_t mmio_mapping; + + svga_t svga; + + rom_t bios_rom; + + uint32_t bank[2]; + uint32_t mask; + + struct + { + uint16_t bg_col, fg_col; + uint16_t width, height; + uint16_t dst_pitch, src_pitch; + uint32_t dst_addr, src_addr; + uint8_t mask, mode, rop; + + uint32_t dst_addr_backup, src_addr_backup; + uint16_t width_backup, height_internal; + int x_count; + } blt; + +} gd5429_t; + +void gd5429_write(uint32_t addr, uint8_t val, void *p); +uint8_t gd5429_read(uint32_t addr, void *p); + +void gd5429_mmio_write(uint32_t addr, uint8_t val, void *p); +uint8_t gd5429_mmio_read(uint32_t addr, void *p); + +void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *p); +void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *p); + +void gd5429_recalc_banking(gd5429_t *gd5429); +void gd5429_recalc_mapping(gd5429_t *gd5429); + +void gd5429_out(uint16_t addr, uint8_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("gd5429 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x3c4: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 5) + { + svga->seqregs[svga->seqaddr & 0x1f] = val; + switch (svga->seqaddr & 0x1f) + { + case 0x10: case 0x30: case 0x50: case 0x70: + case 0x90: case 0xb0: case 0xd0: case 0xf0: + svga->hwcursor.x = (val << 3) | ((svga->seqaddr >> 5) & 7); + pclog("svga->hwcursor.x = %i\n", svga->hwcursor.x); + break; + case 0x11: case 0x31: case 0x51: case 0x71: + case 0x91: case 0xb1: case 0xd1: case 0xf1: + svga->hwcursor.y = (val << 3) | ((svga->seqaddr >> 5) & 7); + pclog("svga->hwcursor.y = %i\n", svga->hwcursor.y); + break; + case 0x12: + svga->hwcursor.ena = val & 1; + pclog("svga->hwcursor.ena = %i\n", svga->hwcursor.ena); + break; + case 0x13: + svga->hwcursor.addr = 0x1fc000 + ((val & 0x3f) * 256); + pclog("svga->hwcursor.addr = %x\n", svga->hwcursor.addr); + break; + + case 0x17: + gd5429_recalc_mapping(gd5429); + break; + } + return; + } + break; + + case 0x3cf: + if (svga->gdcaddr == 5) + { + svga->gdcreg[5] = val; + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + svga->readmode = val & 8; +// pclog("writemode = %i\n", svga->writemode); + return; + } + if (svga->gdcaddr == 6) + { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) + { + svga->gdcreg[6] = val; + gd5429_recalc_mapping(gd5429); + } + svga->gdcreg[6] = val; + return; + } + if (svga->gdcaddr > 8) + { + svga->gdcreg[svga->gdcaddr & 0x3f] = val; + switch (svga->gdcaddr) + { + case 0x09: case 0x0a: case 0x0b: + gd5429_recalc_banking(gd5429); + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + break; + } + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t gd5429_in(uint16_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("IN gd5429 %04X\n", addr); + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr > 5) + { + switch (svga->seqaddr) + { + case 6: + return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; + } + return svga->seqregs[svga->seqaddr & 0x3f]; + } + break; + + case 0x3cf: + if (svga->gdcaddr > 8) + { + return svga->gdcreg[svga->gdcaddr & 0x3f]; + } + break; + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + switch (svga->crtcreg) + { + case 0x27: /*ID*/ + return 0x9c; /*GD5429*/ + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void gd5429_recalc_banking(gd5429_t *gd5429) +{ + svga_t *svga = &gd5429->svga; + + if (svga->gdcreg[0xb] & 0x20) + gd5429->bank[0] = (svga->gdcreg[0x09] & 0x7f) << 14; + else + gd5429->bank[0] = svga->gdcreg[0x09] << 12; + + if (svga->gdcreg[0xb] & 0x01) + { + if (svga->gdcreg[0xb] & 0x20) + gd5429->bank[1] = (svga->gdcreg[0x0a] & 0x7f) << 14; + else + gd5429->bank[1] = svga->gdcreg[0x0a] << 12; + } + else + gd5429->bank[1] = gd5429->bank[0] + 0x8000; +} + +void gd5429_recalc_mapping(gd5429_t *gd5429) +{ + svga_t *svga = &gd5429->svga; + + pclog("Write mapping %02X %i\n", svga->gdcreg[6], svga->seqregs[0x17] & 0x04); + switch (svga->gdcreg[6] & 0x0C) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&gd5429->mmio_mapping); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + if (svga->seqregs[0x17] & 0x04) + mem_mapping_set_addr(&gd5429->mmio_mapping, 0xb8000, 0x00100); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_disable(&gd5429->mmio_mapping); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_disable(&gd5429->mmio_mapping); + svga->banked_mask = 0x7fff; + break; + } +} + +void gd5429_recalctimings(svga_t *svga) +{ + gd5429_t *gd5429 = (gd5429_t *)svga->p; + + if (svga->seqregs[7] & 0x01) + { + svga->render = svga_render_8bpp_highres; + } + + svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); + pclog("MA now %05X %02X\n", svga->ma_latch, svga->crtc[0x1b]); +} + +void gd5429_hwcursor_draw(svga_t *svga, int displine) +{ + int x; + uint8_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + + pclog("HWcursor %i %i %i %i %x %02X %02X\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y, offset, displine, svga->hwcursor_latch.addr, vram[svga->hwcursor_latch.addr], vram[svga->hwcursor_latch.addr + 0x80]); + for (x = 0; x < 32; x += 8) + { + dat[0] = svga->vram[svga->hwcursor_latch.addr]; + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + for (xx = 0; xx < 8; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (dat[1] & 0x80) + ((uint32_t *)buffer32->line[displine])[offset + 32] = 0; + if (dat[0] & 0x80) + ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr++; + } +} + + +void gd5429_write_linear(uint32_t addr, uint8_t val, void *p); + +void gd5429_write(uint32_t addr, uint8_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; +// pclog("gd5429_write : %05X %02X ", addr, val); + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1]; +// pclog("%08X\n", addr); + gd5429_write_linear(addr, val, p); +} + +uint8_t gd5429_read(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + uint8_t ret; +// pclog("gd5429_read : %05X ", addr); + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1]; + ret = svga_read_linear(addr, &gd5429->svga); +// pclog("%08X %02X\n", addr, ret); + return ret; +} + +void gd5429_write_linear(uint32_t addr, uint8_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + uint8_t vala, valb, valc, vald, wm = svga->writemask; + int writemask2 = svga->writemask; + uint32_t raddr = addr; + int plane, mask; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egawrites++; + +// if (svga_output) pclog("Write LFB %08X %02X ", addr, val); + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) + { + writemask2 = 1 << (addr & 3); + addr &= ~3; + } + else if (svga->chain2_write) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + mask = (1 << plane); + if (svga->seqregs[2] & mask) + { + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) return; + if ((raddr <= 0xA0000) || (raddr >= 0xBFFFF)) return; + svga->vram[addr] = val; + + svga->changedvram[addr >> 12] = changeframecount; + } + return; + } + else + { + addr <<= 2; + } + addr &= 0x7fffff; + if (addr >= svga->vram_limit) + return; +// if (svga_output) pclog("%08X\n", addr); + svga->changedvram[addr >> 12] = changeframecount; + + switch (svga->writemode) + { + case 4: + pclog("Writemode 4 : %X ", addr); + addr <<= 1; + svga->changedvram[addr >> 12] = changeframecount; + pclog("%X %X\n", addr, val); + if (val & 0x80) + svga->vram[addr + 0] = svga->gdcreg[1]; + if (val & 0x40) + svga->vram[addr + 1] = svga->gdcreg[1]; + if (val & 0x20) + svga->vram[addr + 2] = svga->gdcreg[1]; + if (val & 0x10) + svga->vram[addr + 3] = svga->gdcreg[1]; + if (val & 0x08) + svga->vram[addr + 4] = svga->gdcreg[1]; + if (val & 0x04) + svga->vram[addr + 5] = svga->gdcreg[1]; + if (val & 0x02) + svga->vram[addr + 6] = svga->gdcreg[1]; + if (val & 0x01) + svga->vram[addr + 7] = svga->gdcreg[1]; + break; + + case 5: + pclog("Writemode 5 : %X ", addr); + addr <<= 1; + svga->changedvram[addr >> 12] = changeframecount; + pclog("%X %X\n", addr, val); + svga->vram[addr + 0] = (val & 0x80) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 1] = (val & 0x40) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 2] = (val & 0x20) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 3] = (val & 0x10) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 4] = (val & 0x08) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 5] = (val & 0x04) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 6] = (val & 0x02) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 7] = (val & 0x01) ? svga->gdcreg[1] : svga->gdcreg[0]; + break; + + case 1: + if (writemask2 & 1) svga->vram[addr] = svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; + break; + case 0: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = val; + if (writemask2 & 2) svga->vram[addr | 0x1] = val; + if (writemask2 & 4) svga->vram[addr | 0x2] = val; + if (writemask2 & 8) svga->vram[addr | 0x3] = val; + } + else + { + if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + } + break; + case 3: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= val; + + vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + svga->gdcreg[8] = wm; + break; + } +} + +void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + pclog("gd5429_start_blit %i\n", count); + if (count == -1) + { + gd5429->blt.dst_addr_backup = gd5429->blt.dst_addr; + gd5429->blt.src_addr_backup = gd5429->blt.src_addr; + gd5429->blt.width_backup = gd5429->blt.width; + gd5429->blt.height_internal = gd5429->blt.height; + gd5429->blt.x_count = gd5429->blt.mask & 7; + pclog("gd5429_start_blit : size %i, %i\n", gd5429->blt.width, gd5429->blt.height); + + if (gd5429->blt.mode & 0x04) + { +// pclog("blt.mode & 0x04\n"); + mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l); + mem_mapping_set_p(&svga->mapping, gd5429); + return; + } + else + { + mem_mapping_set_handler(&gd5429->svga.mapping, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL); + mem_mapping_set_p(&gd5429->svga.mapping, gd5429); + gd5429_recalc_mapping(gd5429); + } + } + + while (count) + { + uint8_t src, dst; + int mask; + + if (gd5429->blt.mode & 0x04) + { + if (gd5429->blt.mode & 0x80) + { + src = (cpu_dat & 0x80) ? gd5429->blt.fg_col : gd5429->blt.bg_col; + mask = cpu_dat & 0x80; + cpu_dat <<= 1; + count--; + } + else + { + src = cpu_dat & 0xff; + cpu_dat >>= 8; + count -= 8; + mask = 1; + } + } + else + { + switch (gd5429->blt.mode & 0xc0) + { + case 0x00: + src = svga->vram[gd5429->blt.src_addr & svga->vrammask]; + gd5429->blt.src_addr += ((gd5429->blt.mode & 0x01) ? -1 : 1); + mask = 1; + break; + case 0x40: + src = svga->vram[(gd5429->blt.src_addr & (svga->vrammask & ~7)) | (gd5429->blt.dst_addr & 7)]; + mask = 1; + break; + case 0x80: + mask = svga->vram[gd5429->blt.src_addr & svga->vrammask] & (0x80 >> gd5429->blt.x_count); + src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col; + gd5429->blt.x_count++; + if (gd5429->blt.x_count == 8) + { + gd5429->blt.x_count = 0; + gd5429->blt.src_addr++; + } + break; + case 0xc0: + mask = svga->vram[gd5429->blt.src_addr & svga->vrammask] & (0x80 >> (gd5429->blt.dst_addr & 7)); + src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col; + break; + } + count--; + } + dst = svga->vram[gd5429->blt.dst_addr & svga->vrammask]; + svga->changedvram[(gd5429->blt.dst_addr & svga->vrammask) >> 12] = changeframecount; + + pclog("Blit %i,%i %06X %06X %06X %02X %02X %02X %02X ", gd5429->blt.width, gd5429->blt.height_internal, gd5429->blt.src_addr, gd5429->blt.dst_addr, gd5429->blt.src_addr & svga->vrammask, svga->vram[gd5429->blt.src_addr & svga->vrammask], 0x80 >> (gd5429->blt.dst_addr & 7), src, dst); + switch (gd5429->blt.rop) + { + case 0x00: dst = 0; break; + case 0x05: dst = src & dst; break; + case 0x06: dst = dst; break; + case 0x09: dst = src & ~dst; break; + case 0x0b: dst = ~ dst; break; + case 0x0d: dst = src; break; + case 0x0e: dst = 0xff; break; + case 0x50: dst = ~ src & dst; break; + case 0x59: dst = src ^ dst; break; + case 0x6d: dst = src | dst; break; + case 0x90: dst = ~(src | dst); break; + case 0x95: dst = ~(src ^ dst); break; + case 0xad: dst = src | ~dst; break; + case 0xd0: dst = ~src; break; + case 0xd6: dst = ~src | dst; break; + case 0xda: dst = ~(src & dst); break; + } + pclog("%02X %02X\n", dst, mask); + + if ((gd5429->blt.width_backup - gd5429->blt.width) >= (gd5429->blt.mask & 7) && + !((gd5429->blt.mode & 0x08) && !mask)) + svga->vram[gd5429->blt.dst_addr & svga->vrammask] = dst; + + gd5429->blt.dst_addr += ((gd5429->blt.mode & 0x01) ? -1 : 1); + + gd5429->blt.width--; + + if (gd5429->blt.width == 0xffff) + { + gd5429->blt.width = gd5429->blt.width_backup; + + gd5429->blt.dst_addr = gd5429->blt.dst_addr_backup = gd5429->blt.dst_addr_backup + ((gd5429->blt.mode & 0x01) ? -gd5429->blt.dst_pitch : gd5429->blt.dst_pitch); + + switch (gd5429->blt.mode & 0xc0) + { + case 0x00: + gd5429->blt.src_addr = gd5429->blt.src_addr_backup = gd5429->blt.src_addr_backup + ((gd5429->blt.mode & 0x01) ? -gd5429->blt.src_pitch : gd5429->blt.src_pitch); + break; + case 0x40: + gd5429->blt.src_addr = ((gd5429->blt.src_addr + ((gd5429->blt.mode & 0x01) ? -8 : 8)) & 0x38) | (gd5429->blt.src_addr & ~0x38); + break; + case 0x80: + if (gd5429->blt.x_count != 0) + { + gd5429->blt.x_count = 0; + gd5429->blt.src_addr++; + } + break; + case 0xc0: + gd5429->blt.src_addr = ((gd5429->blt.src_addr + ((gd5429->blt.mode & 0x01) ? -1 : 1)) & 7) | (gd5429->blt.src_addr & ~7); + break; + } + + gd5429->blt.height_internal--; + if (gd5429->blt.height_internal == 0xffff) + { + if (gd5429->blt.mode & 0x04) + { + mem_mapping_set_handler(&gd5429->svga.mapping, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL); + mem_mapping_set_p(&gd5429->svga.mapping, gd5429); + gd5429_recalc_mapping(gd5429); + } + return; + } + + if (gd5429->blt.mode & 0x04) + return; + } + } +} + +void gd5429_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + pclog("MMIO write %08X %02X\n", addr, val); + switch (addr & 0xff) + { + case 0x00: + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xff00) | val; + break; + case 0x01: + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0x00ff) | (val << 8); + break; + + case 0x04: + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xff00) | val; + break; + case 0x05: + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0x00ff) | (val << 8); + break; + + case 0x08: + gd5429->blt.width = (gd5429->blt.width & 0xff00) | val; + break; + case 0x09: + gd5429->blt.width = (gd5429->blt.width & 0x00ff) | (val << 8); + break; + case 0x0a: + gd5429->blt.height = (gd5429->blt.height & 0xff00) | val; + break; + case 0x0b: + gd5429->blt.height = (gd5429->blt.height & 0x00ff) | (val << 8); + break; + case 0x0c: + gd5429->blt.dst_pitch = (gd5429->blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd5429->blt.dst_pitch = (gd5429->blt.dst_pitch & 0x00ff) | (val << 8); + break; + case 0x0e: + gd5429->blt.src_pitch = (gd5429->blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd5429->blt.src_pitch = (gd5429->blt.src_pitch & 0x00ff) | (val << 8); + break; + + case 0x10: + gd5429->blt.dst_addr = (gd5429->blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd5429->blt.dst_addr = (gd5429->blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd5429->blt.dst_addr = (gd5429->blt.dst_addr & 0x00ffff) | (val << 16); + break; + + case 0x14: + gd5429->blt.src_addr = (gd5429->blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd5429->blt.src_addr = (gd5429->blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd5429->blt.src_addr = (gd5429->blt.src_addr & 0x00ffff) | (val << 16); + break; + + case 0x17: + gd5429->blt.mask = val; + break; + case 0x18: + gd5429->blt.mode = val; + break; + + case 0x1a: + gd5429->blt.rop = val; + break; + + case 0x40: + if (val & 0x02) + gd5429_start_blit(0, -1, gd5429); + break; + } +} + +uint8_t gd5429_mmio_read(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + pclog("MMIO read %08X\n", addr); + switch (addr & 0xff) + { + case 0x40: /*BLT status*/ + return 0; + } + return 0xff; /*All other registers read-only*/ +} + +void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *p) +{ + pclog("gd5429_blt_write_w %08X %08X\n", addr, val); + gd5429_start_blit(val, 16, p); +} + +void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + pclog("gd5429_blt_write_l %08X %08X %04X %04X\n", addr, val, ((val >> 8) & 0x00ff) | ((val << 8) & 0xff00), ((val >> 24) & 0x00ff) | ((val >> 8) & 0xff00)); + if ((gd5429->blt.mode & 0x84) == 0x84) + { + gd5429_start_blit( val & 0xff, 8, p); + gd5429_start_blit((val >> 8) & 0xff, 8, p); + gd5429_start_blit((val >> 16) & 0xff, 8, p); + gd5429_start_blit((val >> 24) & 0xff, 8, p); + } + else + gd5429_start_blit(val, 32, p); +} + +void *gd5429_init() +{ + gd5429_t *gd5429 = malloc(sizeof(gd5429_t)); + svga_t *svga = &gd5429->svga; + memset(gd5429, 0, sizeof(gd5429_t)); + + rom_init(&gd5429->bios_rom, "roms/5429.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&gd5429->svga, gd5429, 1 << 21, /*2mb*/ + gd5429_recalctimings, + gd5429_in, gd5429_out, + gd5429_hwcursor_draw, + NULL); + + mem_mapping_set_handler(&gd5429->svga.mapping, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL); + mem_mapping_set_p(&gd5429->svga.mapping, gd5429); + + mem_mapping_add(&gd5429->mmio_mapping, 0, 0, gd5429_mmio_read, NULL, NULL, gd5429_mmio_write, NULL, NULL, NULL, 0, gd5429); + + io_sethandler(0x03c0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + + svga->hwcursor.yoff = 32; + svga->hwcursor.xoff = 0; + + gd5429->bank[1] = 0x8000; + + return gd5429; +} + +static int gd5429_available() +{ + return rom_present("roms/5429.vbi"); +} + +void gd5429_close(void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + svga_close(&gd5429->svga); + + free(gd5429); +} + +void gd5429_speed_changed(void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + svga_recalctimings(&gd5429->svga); +} + +void gd5429_force_redraw(void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + gd5429->svga.fullchange = changeframecount; +} + +void gd5429_add_status_info(char *s, int max_len, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + svga_add_status_info(s, max_len, &gd5429->svga); +} + +device_t gd5429_device = +{ + "Cirrus Logic GD5429", + DEVICE_NOT_WORKING, + gd5429_init, + gd5429_close, + gd5429_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info +}; diff --git a/src/vid_cl5429.h b/src/vid_cl5429.h new file mode 100644 index 000000000..588590c1b --- /dev/null +++ b/src/vid_cl5429.h @@ -0,0 +1 @@ +extern device_t gd5429_device; diff --git a/src/vid_ega.c b/src/vid_ega.c new file mode 100644 index 000000000..397b56b7e --- /dev/null +++ b/src/vid_ega.c @@ -0,0 +1,1141 @@ +/*EGA emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "timer.h" +#include "video.h" +#include "vid_ega.h" + +extern uint8_t edatlookup[4][4]; + +static uint8_t ega_rotate[8][256]; + +static uint32_t pallook16[256], pallook64[256]; + +/*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/ +int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/ + +static uint8_t mask_gdc[9] = {0x0F, 0x0F, 0x0F, 0x1F, 0x03, 0x3B, 0x0F, 0x0F, 0xFF}; +static uint8_t ega_mask_crtc[0x19] = {0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x1F, 0x1F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x1F, 0xFF, 0x1F, 0x7F, 0xFF}; +static uint8_t mask_seq[5] = {0x03, 0x1F, 0x0F, 0x0F, 0x06}; + +static int old_overscan_color = 0; + +void ega_out(uint16_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + int c; + uint8_t o, old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + if (!ega->attrff) + { + ega->attraddr = val & 31; + if ((val & 0x20) != ega->attr_palette_enable) + { + fullchange = 3; + ega->attr_palette_enable = val & 0x20; + ega_recalctimings(ega); + } + } + else + { + o = ega->attrregs[ega->attraddr & 31]; + ega->attrregs[ega->attraddr & 31] = val; + ega->attrregs[0x11] &= 0x3F; + if (ega->attraddr < 16) + fullchange = changeframecount; + if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) + { + for (c = 0; c < 16; c++) + { + /* if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); + else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); */ + + if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0x3) << 4); + else ega->egapal[c] = (ega->attrregs[c] & 0x3f); + + // if ((ega->attrregs[0x10] & 0x40) && gfxcard != GFX_EGA) ega->egapal[c] |= ((ega->attrregs[0x14] & 0xc) << 4); + if (gfxcard != GFX_EGA) ega->egapal[c] |= ((ega->attrregs[0x14] & 0xc) << 4); + } + } + if ((ega->attraddr == 0x10) || (ega->attraddr == 0x11)) + { + if (o != val) ega_recalctimings(ega); + } + } + ega->attrff ^= 1; + break; + case 0x3c2: + egaswitchread = val & 0xc; + ega->vres = !(val & 0x80); + if (gfxcard == GFX_EGA) + ega->pallook = ega->vres ? pallook16 : pallook64; + else + ega->pallook = pallook64; + ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ + ega->enablevram = (val & 2) ? 1 : 0; + ega->oddeven_page = (val & 0x20) ? 0 : 1; + ega->miscout=val; + if (val & 1) + { +// pclog("Remove mono handler\n"); + io_removehandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + } + else + { +// pclog("Set mono handler\n"); + io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + } + ega_recalctimings(ega); + break; + case 0x3c4: + ega->seqaddr = val; + break; + case 0x3c5: + if (ega->seqaddr <= 4) val &= mask_seq[ega->seqaddr]; + o = ega->seqregs[ega->seqaddr & 0xf]; + ega->seqregs[ega->seqaddr & 0xf] = val; + if (o != val && (ega->seqaddr & 0xf) == 1) + ega_recalctimings(ega); + switch (ega->seqaddr & 0xf) + { + case 1: + if (ega->scrblank && !(val & 0x20)) + fullchange = 3; + ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); + break; + case 2: + ega->writemask = val & 0xf; + break; + case 3: + ega->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + ega->charseta = ((val & 3) * 0x10000) + 2; + break; + case 4: + ega->chain2_write = !(val & 4); + break; + } + break; + case 0x3ce: + ega->gdcaddr = val; + break; + case 0x3cf: + if (ega->seqaddr <= 8) val &= mask_gdc[ega->gdcaddr]; + ega->gdcreg[ega->gdcaddr & 15] = val; + switch (ega->gdcaddr & 15) + { + case 2: + ega->colourcompare = val; + break; + case 4: + ega->readplane = val & 3; + break; + case 5: + ega->writemode = val & 3; + ega->readmode = val & 8; + ega->chain2_read = val & 0x10; + break; + case 6: +// pclog("Write mapping %02X\n", val); + switch (val & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000); + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000); + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000); + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000); + break; + } + break; + case 7: + ega->colournocare = val; + break; + } + break; + case 0x3d4: + // pclog("Write 3d4 %02X %04X:%04X\n", val, CS, cpu_state.pc); + ega->crtcreg = val & 31; + return; + case 0x3d5: + // pclog("Write 3d5 %02X %02X %02X\n", ega->crtcreg, val, ega->crtc[0x11]); +// if (ega->crtcreg == 1 && val == 0x14) +// fatal("Here\n"); + if (ega->crtcreg <= 0x18) val &= ega_mask_crtc[ega->crtcreg]; + if (ega->crtcreg <= 7 && ega->crtc[0x11] & 0x80) return; + old = ega->crtc[ega->crtcreg]; + ega->crtc[ega->crtcreg] = val; + if (old != val) + { + if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) + { + fullchange = changeframecount; + ega_recalctimings(ega); + } + } + break; + } +} + +uint8_t ega_in(uint16_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + +/* if (addr != 0x3da && addr != 0x3ba) + pclog("ega_in %04X\n", addr); */ + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + return ega->attraddr; + case 0x3c1: + if (ega->attraddr == 0x10) return ((ega->attrregs[ega->attraddr] & 0x7F) | (ega->attrff << 7)); + return ega->attrregs[ega->attraddr]; + case 0x3c2: +// printf("Read egaswitch %02X %02X %i\n",egaswitchread,egaswitches,VGA); + switch (egaswitchread) + { + case 0xc: return (egaswitches & 1) ? 0x10 : 0; + case 0x8: return (egaswitches & 2) ? 0x10 : 0; + case 0x4: return (egaswitches & 4) ? 0x10 : 0; + case 0x0: return (egaswitches & 8) ? 0x10 : 0; + } + break; + case 0x3c4: + return ega->seqaddr; + case 0x3c5: + return ega->seqregs[ega->seqaddr & 0xf]; + case 0x3ce: + return ega->gdcaddr; + case 0x3cf: + if (ega->gdcaddr == 0xF8) return ega->la; + if (ega->gdcaddr == 0xF9) return ega->lb; + if (ega->gdcaddr == 0xFA) return ega->lc; + if (ega->gdcaddr == 0xFB) return ega->ld; + return ega->gdcreg[ega->gdcaddr & 0xf]; + case 0x3d4: + return ega->crtcreg; + case 0x3d5: + return ega->crtc[ega->crtcreg]; + case 0x3da: + ega->attrff = 0; + // ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/ + if (ega->stat & 0x01) + ega->stat &= ~0x30; + else + ega->stat ^= 0x30; + return ega->stat; + } +// printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,cpu_state.pc); + return 0xff; +} + +void ega_recalctimings(ega_t *ega) +{ + double _dispontime, _dispofftime, disptime; + double crtcconst; + + ega->vtotal = ega->crtc[6]; + ega->dispend = ega->crtc[0x12]; + ega->vsyncstart = ega->crtc[0x10]; + ega->split = ega->crtc[0x18]; + ega->vblankstart = ega->crtc[0x15]; + + if (ega->crtc[7] & 1) ega->vtotal |= 0x100; + ega->vtotal++; + + if (ega->crtc[7] & 2) ega->dispend |= 0x100; + ega->dispend++; + + if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; + ega->vsyncstart++; + + if (ega->crtc[7] & 0x10) ega->split |= 0x100; + ega->split+=2; + + if (ega->crtc[7] & 0x08) ega->vblankstart |= 0x100; + ega->vblankstart++; + + ega->hdisp = ega->crtc[1]; + ega->hdisp++; + + ega->rowoffset = ega->crtc[0x13]; + + // printf("Recalc! %i %i %i %i %i %02X\n", ega->vtotal, ega->dispend, ega->vsyncstart, ega->split, ega->hdisp, ega->attrregs[0x16]); + + if (ega->vblankstart < ega->dispend) + ega->dispend = ega->vblankstart; + + if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); + else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0)); + + disptime = ega->crtc[0] + 2; + _dispontime = ega->hdisp; + +// printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8); + if (ega->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + ega->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + ega->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + + /* pclog("dispontime %i (%f) dispofftime %i (%f)\n", ega->dispontime, (float)ega->dispontime / (1 << TIMER_SHIFT), + ega->dispofftime, (float)ega->dispofftime / (1 << TIMER_SHIFT)); */ +// printf("EGA horiz total %i display end %i clock rate %i vidclock %i %i\n",crtc[0],crtc[1],egaswitchread,vidclock,((ega3c2>>2)&3) | ((tridentnewctrl2<<2)&4)); +// printf("EGA vert total %i display end %i max row %i vsync %i\n",ega_vtotal,ega_dispend,(crtc[9]&31)+1,ega_vsyncstart); +// printf("total %f on %f cycles off %f cycles frame %f sec %f %02X\n",disptime*crtcconst,dispontime,dispofftime,(dispontime+dispofftime)*ega_vtotal,(dispontime+dispofftime)*ega_vtotal*70,seqregs[1]); +} + +void ega_poll(void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t chr, dat, attr; + uint32_t charaddr; + int x, xx; + uint32_t fg, bg; + int offset; + uint8_t edat[4]; + int drawcursor = 0; + uint32_t addr_ex = 0; + int y_add = enable_overscan ? 14 : 0; + int x_add = enable_overscan ? 8 : 0; + int y_add_ex = enable_overscan ? 28 : 0; + int x_add_ex = enable_overscan ? 16 : 0; + uint32_t *q, *r, i, j; + + if (!ega->linepos) + { + ega->vidtime += ega->dispofftime; + + ega->stat |= 1; + ega->linepos = 1; + + if (ega->dispon) + { + if (ega->firstline == 2000) + ega->firstline = ega->displine; + + if (ega->scrblank) + { + for (x = 0; x < ega->hdisp; x++) + { + switch (ega->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 9) + xx + 32 + x_add] = 0; + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 8) + xx + 32 + x_add] = 0; + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 18) + xx + 32 + x_add] = 0; + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 16) + xx + 32 + x_add] = 0; + break; + } + } + } + else if (!ega->scrblank && ega->attr_palette_enable) + { + if (!(ega->gdcreg[6] & 1)) + { + if (fullchange) + { + for (x = 0; x < ega->hdisp; x++) + { + drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + addr_ex = (ega->oddeven_page ? 0x10000 : 0); + chr = ega->vram[(ega->ma << 1) | addr_ex]; + attr = ega->vram[((ega->ma << 1) + 1) | addr_ex]; + + if (attr & 8) charaddr = ega->charsetb + (chr * 128); + else charaddr = ega->charseta + (chr * 128); + + if (drawcursor) + { + bg = ega->pallook[ega->egapal[attr & 15]]; + fg = ega->pallook[ega->egapal[attr >> 4]]; + } + else + { + fg = ega->pallook[ega->egapal[attr & 15]]; + bg = ega->pallook[ega->egapal[attr >> 4]]; + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + if (ega->blink & 16) + fg = bg; + } + } + + dat = ega->vram[charaddr + (ega->sc << 2)]; + if (ega->seqregs[1] & 8) + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x << 4) + 32 + (xx << 1)) & 2047) + x_add] = + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x << 4) + 33 + (xx << 1)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + (xx << 1)) & 2047) + x_add] = + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 33 + (xx << 1)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 16) & 2047) + x_add] = + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 17) & 2047) + x_add] = bg; + else + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 16) & 2047) + x_add] = + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 17) & 2047) + x_add] = (dat & 1) ? fg : bg; + } + } + else + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x << 3) + 32 + xx) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 9) + 32 + xx) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 9) + 32 + 8) & 2047) + x_add] = bg; + else + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 9) + 32 + 8) & 2047) + x_add] = (dat & 1) ? fg : bg; + } + } + ega->ma += 4; + ega->ma &= ega->vrammask; + } + } + } + else + { + switch (ega->gdcreg[5] & 0x20) + { + case 0x00: + if (ega->seqregs[1] & 8) + { + offset = ((8 - ega->scrollcache) << 1) + 16; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[ega->ma | 0x8000]; + edat[1] = ega->vram[ega->ma | 0x8001]; + edat[2] = ega->vram[ega->ma | 0x8002]; + edat[3] = ega->vram[ega->ma | 0x8003]; + } + else + { + edat[0] = ega->vram[ega->ma]; + edat[1] = ega->vram[ega->ma | 0x1]; + edat[2] = ega->vram[ega->ma | 0x2]; + edat[3] = ega->vram[ega->ma | 0x3]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 14 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } + } + else + { + offset = (8 - ega->scrollcache) + 24; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[ega->ma | 0x8000]; + edat[1] = ega->vram[ega->ma | 0x8001]; + edat[2] = ega->vram[ega->ma | 0x8002]; + edat[3] = ega->vram[ega->ma | 0x8003]; + } + else + { + edat[0] = ega->vram[ega->ma]; + edat[1] = ega->vram[ega->ma | 0x1]; + edat[2] = ega->vram[ega->ma | 0x2]; + edat[3] = ega->vram[ega->ma | 0x3]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 6 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 4 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 2 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } + } + break; + case 0x20: + offset = ((8 - ega->scrollcache) << 1) + 16; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[(ega->ma << 1) + 0x8000]; + edat[1] = ega->vram[(ega->ma << 1) + 0x8001]; + } + else + { + edat[0] = ega->vram[(ega->ma << 1)]; + edat[1] = ega->vram[(ega->ma << 1) + 1]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 14 + offset + x_add]= ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[edat[1] & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; + } + break; + } + } + } + if (ega->lastline < ega->displine) + ega->lastline = ega->displine; + } + + ega->displine++; + if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) + ega->stat &= ~8; + ega->vslines++; + if (ega->displine > 500) + ega->displine = 0; + } + else + { + ega->vidtime += ega->dispontime; +// if (output) printf("Display on %f\n",vidtime); + if (ega->dispon) + ega->stat &= ~1; + ega->linepos = 0; + if (ega->sc == (ega->crtc[11] & 31)) + ega->con = 0; + if (ega->dispon) + { + if (ega->sc == (ega->crtc[9] & 31)) + { + ega->sc = 0; + + ega->maback += (ega->rowoffset << 3); + ega->maback &= ega->vrammask; + ega->ma = ega->maback; + } + else + { + ega->sc++; + ega->sc &= 31; + ega->ma = ega->maback; + } + } + ega->vc++; + ega->vc &= 1023; +// printf("Line now %i %i ma %05X\n",vc,displine,ma); + if (ega->vc == ega->split) + { +// printf("Split at line %i %i\n",displine,vc); + ega->ma = ega->maback = 0; + if (ega->attrregs[0x10] & 0x20) + ega->scrollcache = 0; + } + if (ega->vc == ega->dispend) + { +// printf("Display over at line %i %i\n",displine,vc); + ega->dispon=0; + if (ega->crtc[10] & 0x20) ega->cursoron = 0; + else ega->cursoron = ega->blink & 16; + if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) + fullchange = 2; + ega->blink++; + + if (fullchange) + fullchange--; + } + if (ega->vc == ega->vsyncstart) + { + int wx = 0; + int wy = 0; + ega->dispon = 0; +// printf("Vsync on at line %i %i\n",displine,vc); + ega->stat |= 8; + if (ega->seqregs[1] & 8) x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9) * 2; + else x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9); +// pclog("Cursor %02X %02X\n",crtc[10],crtc[11]); +// pclog("Firstline %i Lastline %i wx %i %i\n",firstline,lastline,wx,oddeven); +// doblit(); + if (x != xsize || (ega->lastline - ega->firstline) != ysize) + { + xsize = x; + ysize = ega->lastline - ega->firstline; + if (xsize < 64) xsize = 640; + if (ysize < 32) ysize = 200; + if (ega->vres) + updatewindowsize(xsize + x_add_ex, (ysize << 1) + y_add_ex); + else + updatewindowsize(xsize + x_add_ex, ysize + y_add_ex); + } + +startblit(); + if (enable_overscan) + { + if ((x >= 160) && ((ega->lastline - ega->firstline) >= 120)) + { + for (i = 0; i < 14; i++) + { + q = &((uint32_t *)buffer32->line[i])[32]; + r = &((uint32_t *)buffer32->line[ysize + y_add_ex - 1 - i])[32]; + + for (j = 0; j < (xsize + x_add_ex); j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + r[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + + for (i = 14; i < (ysize + 14); i ++) + { + q = &((uint32_t *)buffer32->line[i])[32]; + + for (j = 0; j < 8; j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + q[xsize + x_add_ex - 1 - j] = ega->pallook[ega->attrregs[0x11]]; + } + } + } + } + + video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline + y_add_ex, xsize + x_add_ex, ega->lastline - ega->firstline + y_add_ex); + endblit(); + + frames++; + + ega->video_res_x = wx; + ega->video_res_y = wy + 1; + if (!(ega->gdcreg[6] & 1)) /*Text mode*/ + { + ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + ega->video_bpp = 0; + } + else + { + if (ega->crtc[9] & 0x80) + ega->video_res_y /= 2; + if (!(ega->crtc[0x17] & 1)) + ega->video_res_y *= 2; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + if (ega->seqregs[1] & 8) + ega->video_res_x /= 2; + ega->video_bpp = (ega->gdcreg[5] & 0x20) ? 2 : 4; + } + +// wakeupblit(); + readflash=0; + //framecount++; + ega->firstline = 2000; + ega->lastline = 0; + + ega->maback = ega->ma = (ega->crtc[0xc] << 8)| ega->crtc[0xd]; + ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; + ega->ma <<= 2; + ega->maback <<= 2; + ega->ca <<= 2; + changeframecount = 2; + ega->vslines = 0; + } + if (ega->vc == ega->vtotal) + { + ega->vc = 0; + ega->sc = 0; + ega->dispon = 1; + ega->displine = 0; + ega->scrollcache = ega->attrregs[0x13] & 7; + } + if (ega->sc == (ega->crtc[10] & 31)) + ega->con = 1; + } +} + +void ega_write(uint32_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t vala, valb, valc, vald; + int writemask2 = ega->writemask; + uint32_t raddr = addr; + int plane, mask; + + egawrites++; + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + + if (addr >= 0xB0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_write) + { + plane = (ega->readplane & 2) | (addr & 1); + mask = (1 << plane); + if (ega->seqregs[2] & mask) + { + addr = ((addr & ~1) << 2) | plane | (ega->oddeven_page ? 0x10000 : 0); + if ((!ega->extvram) && (addr >= 0x10000)) return; + if (addr >= 0x40000) return; + if ((raddr <= 0xA0000) || (raddr >= 0xBFFFF)) return; + ega->vram[addr] = val; + } + return; + } + + addr <<= 2; + + if (!(ega->gdcreg[6] & 1)) + fullchange = 2; + +// pclog("%i %08X %i %i %02X %02X %02X %02X %02X\n",chain4,addr,writemode,writemask,gdcreg[8],vram[0],vram[1],vram[2],vram[3]); + switch (ega->writemode) + { + case 1: + if (writemask2 & 1) ega->vram[addr] = ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld; + break; + case 0: + if (ega->gdcreg[3] & 7) + val = ega_rotate[ega->gdcreg[3] & 7][val]; + + if (ega->gdcreg[8] == 0xff && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = val; + if (writemask2 & 2) ega->vram[addr | 0x1] = val; + if (writemask2 & 4) ega->vram[addr | 0x2] = val; + if (writemask2 & 8) ega->vram[addr | 0x3] = val; + } + else + { + if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; +// pclog("Write %02X %01X %02X %02X %02X %02X %02X\n",gdcreg[3]&0x18,writemask,vala,valb,valc,vald,gdcreg[8]); + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } + } + break; + } +} + +uint8_t ega_read(uint32_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t temp, temp2, temp3, temp4; + int readplane = ega->readplane; + int plane; + + egareads++; + cycles -= video_timing_b; + cycles_lost += video_timing_b; +// pclog("Readega %06X ",addr); + if (addr >= 0xb0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_read) + { + plane = (ega->readplane & 2) | (addr & 1); + addr = ((addr & ~1) << 2) | plane | (ega->oddeven_page ? 0x10000 : 0); + if ((!ega->extvram) && (addr >= 0x10000)) return 0xff; + if (addr >= 0x40000) return 0xff; + return ega->vram[addr]; + } + + addr <<= 2; + + ega->la = ega->vram[addr]; + ega->lb = ega->vram[addr | 0x1]; + ega->lc = ega->vram[addr | 0x2]; + ega->ld = ega->vram[addr | 0x3]; + if (ega->readmode) + { + temp = (ega->colournocare & 1) ? 0xff : 0; + temp &= ega->la; + temp ^= (ega->colourcompare & 1) ? 0xff : 0; + temp2 = (ega->colournocare & 2) ? 0xff : 0; + temp2 &= ega->lb; + temp2 ^= (ega->colourcompare & 2) ? 0xff : 0; + temp3 = (ega->colournocare & 4) ? 0xff : 0; + temp3 &= ega->lc; + temp3 ^= (ega->colourcompare & 4) ? 0xff : 0; + temp4 = (ega->colournocare & 8) ? 0xff : 0; + temp4 &= ega->ld; + temp4 ^= (ega->colourcompare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } + return ega->vram[addr | readplane]; +} + +void ega_init(ega_t *ega) +{ + int c, d, e; + + ega->vram = malloc(0x40000); + ega->vrammask = 0x3ffff; + + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + ega_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + + for (c = 0; c < 4; c++) + { + for (d = 0; d < 4; d++) + { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; + } + } + + for (c = 0; c < 256; c++) + { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); + if ((c & 0x17) == 6) + pallook16[c] = makecol32(0xaa, 0x55, 0); + } + ega->pallook = pallook16; +} + +void ega_common_defaults(ega_t *ega) +{ + ega->miscout |= 0x22; + ega->enablevram = 1; + ega->oddeven_page = 0; + + ega->seqregs[4] |= 2; + ega->extvram = 1; +} + +void *ega_standalone_init() +{ + int c, d, e; + ega_t *ega = malloc(sizeof(ega_t)); + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + rom_init(&ega->bios_rom, "roms/ibm_6277356_ega_card_u44_27128.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + ega->crtc[0] = 63; + ega->dispontime = 1000 * (1 << TIMER_SHIFT); + ega->dispofftime = 1000 * (1 << TIMER_SHIFT); + ega->dispontime <<= 1; + ega->dispofftime <<= 1; + + ega_init(ega); + + ega_common_defaults(ega); + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + vramp = ega->vram; + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +void *cpqega_standalone_init() +{ + int c, d, e; + ega_t *ega = malloc(sizeof(ega_t)); + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + rom_init(&ega->bios_rom, "roms/108281-001.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + // pclog("Read EGA ROM in reverse\n"); + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + ega->crtc[0] = 63; + // ega->crtc[6] = 255; + ega->dispontime = 1000 * (1 << TIMER_SHIFT); + ega->dispofftime = 1000 * (1 << TIMER_SHIFT); + + ega_init(ega); + // ega->attrregs[0x10] |= 0xF7; + + ega_common_defaults(ega); + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + vramp = ega->vram; + // io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +void *sega_standalone_init() +{ + int c, d, e; + ega_t *ega = malloc(sizeof(ega_t)); + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + rom_init(&ega->bios_rom, "roms/lega.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + // pclog("Read EGA ROM in reverse\n"); + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + ega->crtc[0] = 63; + // ega->crtc[6] = 255; + ega->dispontime = 1000 * (1 << TIMER_SHIFT); + ega->dispofftime = 1000 * (1 << TIMER_SHIFT); + + ega_init(ega); + // ega->attrregs[0x10] |= 0xF7; + + ega_common_defaults(ega); + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + vramp = ega->vram; + // io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +static int ega_standalone_available() +{ + return rom_present("roms/ibm_6277356_ega_card_u44_27128.bin"); +} + +static int cpqega_standalone_available() +{ + return rom_present("roms/108281-001.bin"); +} + +static int sega_standalone_available() +{ + return rom_present("roms/lega.vbi"); +} + +void ega_close(void *p) +{ + ega_t *ega = (ega_t *)p; + + free(ega->vram); + free(ega); +} + +void ega_speed_changed(void *p) +{ + ega_t *ega = (ega_t *)p; + + ega_recalctimings(ega); +} + +device_t ega_device = +{ + "EGA", + 0, + ega_standalone_init, + ega_close, + ega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; + +device_t cpqega_device = +{ + "Compaq EGA", + 0, + cpqega_standalone_init, + ega_close, + cpqega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; + +device_t sega_device = +{ + "SuperEGA", + 0, + sega_standalone_init, + ega_close, + sega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_ega.h b/src/vid_ega.h new file mode 100644 index 000000000..efab56379 --- /dev/null +++ b/src/vid_ega.h @@ -0,0 +1,80 @@ +typedef struct ega_t +{ + mem_mapping_t mapping; + + rom_t bios_rom; + + uint8_t crtcreg; + uint8_t crtc[32]; + uint8_t gdcreg[16]; + int gdcaddr; + uint8_t attrregs[32]; + int attraddr, attrff; + int attr_palette_enable; + uint8_t seqregs[64]; + int seqaddr; + + uint8_t miscout; + int vidclock; + + uint8_t la, lb, lc, ld; + + uint8_t stat; + + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + int chain4, chain2_read, chain2_write; + int oddeven_page; + int enablevram, extvram; + uint8_t writemask; + uint32_t charseta, charsetb; + + uint8_t egapal[16]; + uint32_t *pallook; + + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int linedbl, rowcount; + double clock; + uint32_t ma_latch; + + int vres; + + int dispontime, dispofftime; + int vidtime; + + uint8_t scrblank; + + int dispon; + int hdisp_on; + + uint32_t ma, maback, ca; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink; + int scrollcache; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + + uint8_t *vram; + int vrammask; + + int video_res_x, video_res_y, video_bpp; +} ega_t; + +void *ega_standalone_init(); +void ega_out(uint16_t addr, uint8_t val, void *p); +uint8_t ega_in(uint16_t addr, void *p); +void ega_poll(void *p); +void ega_recalctimings(struct ega_t *ega); +void ega_write(uint32_t addr, uint8_t val, void *p); +uint8_t ega_read(uint32_t addr, void *p); + +extern device_t ega_device; +extern device_t cpqega_device; +extern device_t sega_device; diff --git a/src/vid_et4000.c b/src/vid_et4000.c new file mode 100644 index 000000000..7b0583531 --- /dev/null +++ b/src/vid_et4000.c @@ -0,0 +1,211 @@ +/*ET4000 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_unk_ramdac.h" + +#include "vid_et4000.h" + +typedef struct et4000_t +{ + svga_t svga; + unk_ramdac_t ramdac; + + rom_t bios_rom; + + uint8_t banking; +} et4000_t; + +static uint8_t crtc_mask[0x40] = +{ + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void et4000_out(uint16_t addr, uint8_t val, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("ET4000 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + unk_ramdac_out(addr, val, &et4000->ramdac, svga); + return; + + case 0x3CD: /*Banking*/ + svga->write_bank = (val & 0xf) * 0x10000; + svga->read_bank = ((val >> 4) & 0xf) * 0x10000; + et4000->banking = val; +// pclog("Banking write %08X %08X %02X\n", svga->write_bank, svga->read_bank, val); + return; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + // pclog("ET4000 Write: CRTC %02X = %02X\n", svga->crtcreg, val); + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t et4000_in(uint16_t addr, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr); + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 7) return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return unk_ramdac_in(addr, &et4000->ramdac, svga); + + case 0x3CD: /*Banking*/ + return et4000->banking; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void et4000_recalctimings(svga_t *svga) +{ + et4000_t *et4000 = (et4000_t *)svga->p; + + svga->ma_latch |= (svga->crtc[0x33]&3)<<16; + if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 4) svga->dispend += 0x400; + if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (!svga->rowoffset) svga->rowoffset = 0x100; + if (svga->crtc[0x3f] & 1) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + +// pclog("Rowoffset %i\n",svga_rowoffset); + + switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) + { + case 0: case 1: break; + case 3: svga->clock = cpuclock / 40000000.0; break; + case 5: svga->clock = cpuclock / 65000000.0; break; + default: svga->clock = cpuclock / 36000000.0; break; + } + + switch (svga->bpp) + { + case 15: case 16: + svga->hdisp /= 2; + break; + case 24: + svga->hdisp /= 3; + break; + } +} + +void *et4000_init() +{ + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + rom_init(&et4000->bios_rom, "roms/et4000.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ + et4000_recalctimings, + et4000_in, et4000_out, + NULL, + NULL); + + return et4000; +} + +static int et4000_available() +{ + return rom_present("roms/et4000.BIN"); +} + +void et4000_close(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_close(&et4000->svga); + + free(et4000); +} + +void et4000_speed_changed(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_recalctimings(&et4000->svga); +} + +void et4000_force_redraw(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + et4000->svga.fullchange = changeframecount; +} + +void et4000_add_status_info(char *s, int max_len, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_add_status_info(s, max_len, &et4000->svga); +} + +device_t et4000_device = +{ + "Tseng Labs ET4000AX", + 0, + et4000_init, + et4000_close, + et4000_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_add_status_info +}; diff --git a/src/vid_et4000.h b/src/vid_et4000.h new file mode 100644 index 000000000..a20f8820d --- /dev/null +++ b/src/vid_et4000.h @@ -0,0 +1 @@ +extern device_t et4000_device; diff --git a/src/vid_et4000w32.c b/src/vid_et4000w32.c new file mode 100644 index 000000000..a46a040dc --- /dev/null +++ b/src/vid_et4000w32.c @@ -0,0 +1,1451 @@ +/*ET4000/W32p emulation (Diamond Stealth 32)*/ +/*Known bugs : + + - Accelerator doesn't work in planar modes +*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_icd2061.h" +#include "vid_stg_ramdac.h" + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (et4000->fifo_write_idx - et4000->fifo_read_idx) +#define FIFO_FULL ((et4000->fifo_write_idx - et4000->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (et4000->fifo_read_idx == et4000->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_MMU = (0x02 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct et4000w32p_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmu_mapping; + + rom_t bios_rom; + + svga_t svga; + stg_ramdac_t ramdac; + icd2061_t icd2061; + + int index; + uint8_t regs[256]; + uint32_t linearbase, linearbase_old; + + uint8_t banking, banking2; + + uint8_t pci_regs[256]; + + int vram_size; + int interleaved; + int max_ram_mask; + int revision; + + /*Accelerator*/ + struct + { + struct + { + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint16_t pattern_off,source_off,dest_off,mix_off; + uint8_t pixel_depth,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + uint16_t error; + uint16_t dmin,dmaj; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint32_t pattern_back,source_back,dest_back,mix_back; + int pattern_x,source_x; + int pattern_x_back,source_x_back; + int pattern_y,source_y; + uint8_t status; + uint64_t cpu_dat; + int cpu_dat_pos; + int pix_pos; + } acl; + + struct + { + uint32_t base[3]; + uint8_t ctrl; + } mmu; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; +} et4000w32p_t; + +void et4000w32p_recalcmapping(et4000w32p_t *et4000); + +uint8_t et4000w32p_mmu_read(uint32_t addr, void *p); +void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p); + +void et4000w32_blit_start(et4000w32p_t *et4000); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000); + +void et4000w32p_out(uint16_t addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + uint8_t old; + +// pclog("et4000w32p_out: addr %04X val %02X %04X:%04X %02X %02X\n", addr, val, CS, pc, ram[0x487], ram[0x488]); + +/* if (ram[0x487] == 0x62) + fatal("mono\n");*/ +// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("ET4000W32p out %04X %02X %04X:%04X ",addr,val,CS,pc); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("%04X\n",addr); + + switch (addr) + { + case 0x3c2: + if (gfxcard == GFX_ET4000W32) + icd2061_write(&et4000->icd2061, (val >> 2) & 3); + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + stg_ramdac_out(addr, val, &et4000->ramdac, svga); + return; + + case 0x3CB: /*Banking extension*/ + svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20); + svga->read_bank = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16); + et4000->banking2 = val; + return; + case 0x3CD: /*Banking*/ + svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536); + svga->read_bank = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536); + et4000->banking = val; + return; + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 6: + svga->gdcreg[svga->gdcaddr & 15] = val; + //et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4); + et4000w32p_recalcmapping(et4000); + return; + } + break; + case 0x3D4: + svga->crtcreg = val & 63; + return; + case 0x3D5: +// pclog("Write CRTC R%02X %02X\n", crtcreg, val); + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + if (svga->crtcreg == 0x30) + { + et4000->linearbase = val * 0x400000; +// pclog("Linear base now at %08X %02X\n", et4000w32p_linearbase, val); + et4000w32p_recalcmapping(et4000); + } + if (svga->crtcreg == 0x32 || svga->crtcreg == 0x36) + et4000w32p_recalcmapping(et4000); + break; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + et4000->index=val; + return; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + et4000->regs[et4000->index] = val; + svga->hwcursor.x = et4000->regs[0xE0] | ((et4000->regs[0xE1] & 7) << 8); + svga->hwcursor.y = et4000->regs[0xE4] | ((et4000->regs[0xE5] & 7) << 8); + svga->hwcursor.addr = (et4000->regs[0xE8] | (et4000->regs[0xE9] << 8) | ((et4000->regs[0xEA] & 7) << 16)) << 2; + svga->hwcursor.addr += (et4000->regs[0xE6] & 63) * 16; + svga->hwcursor.ena = et4000->regs[0xF7] & 0x80; + svga->hwcursor.xoff = et4000->regs[0xE2] & 63; + svga->hwcursor.yoff = et4000->regs[0xE6] & 63; +// pclog("HWCURSOR X %i Y %i\n",svga->hwcursor_x,svga->hwcursor_y); + return; + + } + svga_out(addr, val, svga); +} + +uint8_t et4000w32p_in(uint16_t addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + uint8_t temp; +// if (addr==0x3DA) pclog("In 3DA %04X(%06X):%04X\n",CS,cs,pc); + +// pclog("ET4000W32p in %04X %04X:%04X ",addr,CS,pc); + +// if (addr != 0x3da && addr != 0x3ba) +// pclog("et4000w32p_in: addr %04X %04X:%04X %02X %02X\n", addr, CS, pc, ram[0x487], ram[0x488]); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("%04X\n",addr); + + switch (addr) + { + case 0x3c5: + if ((svga->seqaddr & 0xf) == 7) + return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return stg_ramdac_in(addr, &et4000->ramdac, svga); + + case 0x3CB: + return et4000->banking2; + case 0x3CD: + return et4000->banking; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: +// pclog("Read CRTC R%02X %02X\n", crtcreg, crtc[crtcreg]); + return svga->crtc[svga->crtcreg]; + + case 0x3DA: + if (gfxcard == GFX_ET4000W32C) break; + svga->attrff = 0; + svga->cgastat ^= 0x30; + temp = svga->cgastat & 0x39; + if (svga->hdisp_on) temp |= 2; + if (!(svga->cgastat & 8)) temp |= 0x80; +// pclog("3DA in %02X\n",temp); + return temp; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + return et4000->index; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + if (et4000->index==0xec) + return (et4000->regs[0xec] & 0xf) | 0x60; /*ET4000/W32p rev D*/ + if (et4000->index == 0xef) + { + if (PCI) return et4000->regs[0xef] | 0xe0; /*PCI*/ + else return et4000->regs[0xef] | 0x60; /*VESA local bus*/ + } + return et4000->regs[et4000->index]; + } + return svga_in(addr, svga); +} + +void et4000w32p_recalctimings(svga_t *svga) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; +// pclog("Recalc %08X ",svga_ma); + svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; +// pclog("SVGA_MA %08X %i\n", svga_ma, (svga_miscout >> 2) & 3); + if (svga->crtc[0x35] & 0x01) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 0x02) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 0x04) svga->dispend += 0x400; + if (svga->crtc[0x35] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (svga->crtc[0x3F] & 0x80) svga->rowoffset += 0x100; + if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + + if (gfxcard == GFX_ET4000W32) + { + switch ((svga->miscout >> 2) & 3) + { + case 0: case 1: break; + case 2: case 3: svga->clock = cpuclock / icd2061_getfreq(&et4000->icd2061, 2); break; + } + } + else + { + svga->clock = cpuclock / stg_getclock((svga->miscout >> 2) & 3, &et4000->ramdac); + } + + switch (svga->bpp) + { + case 15: case 16: + svga->hdisp >>= 1; + break; + case 24: + svga->hdisp /= 3; + break; + } +} + +void et4000w32p_recalcmapping(et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + + if (!(et4000->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->linear_mapping); + mem_mapping_disable(&et4000->mmu_mapping); + return; + } + + pclog("recalcmapping %p\n", svga); + if (svga->crtc[0x36] & 0x10) /*Linear frame buffer*/ + { + mem_mapping_set_addr(&et4000->linear_mapping, et4000->linearbase, 0x200000); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->mmu_mapping); + } + else + { + int map = (svga->gdcreg[6] & 0xc) >> 2; + if (svga->crtc[0x36] & 0x20) map |= 4; + if (svga->crtc[0x36] & 0x08) map |= 8; + switch (map) + { + case 0x0: case 0x4: case 0x8: case 0xC: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x1: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x2: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x3: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x5: case 0x9: case 0xD: /*64k at A0000, MMU at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xb8000, 0x08000); + svga->banked_mask = 0xffff; + break; + case 0x6: case 0xA: case 0xE: /*32k at B0000, MMU at A8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0x7: case 0xB: case 0xF: /*32k at B8000, MMU at A8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + mem_mapping_disable(&et4000->linear_mapping); +// pclog("ET4K map %02X\n", map); + } + et4000->linearbase_old = et4000->linearbase; + + if (!et4000->interleaved && (et4000->svga.crtc[0x32] & 0x80)) + mem_mapping_disable(&svga->mapping); +} + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +static void et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + switch (addr & 0x7fff) + { + case 0x7f80: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFFFF00) | val; break; + case 0x7f81: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7f82: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7f83: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7f84: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFFFF00) | val; break; + case 0x7f85: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7f86: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7f87: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7f88: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0xFF00) | val; break; + case 0x7f89: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0x00FF) | (val << 8); break; + case 0x7f8a: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0xFF00) | val; break; + case 0x7f8b: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0x00FF) | (val << 8); break; + case 0x7f8c: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0xFF00) | val; break; + case 0x7f8d: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00FF) | (val << 8); break; + case 0x7f8e: et4000->acl.queued.pixel_depth = val; break; + case 0x7f8f: et4000->acl.queued.xy_dir = val; break; + case 0x7f90: et4000->acl.queued.pattern_wrap = val; break; + case 0x7f92: et4000->acl.queued.source_wrap = val; break; + case 0x7f98: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0xFF00) | val; break; + case 0x7f99: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0x00FF) | (val << 8); break; + case 0x7f9a: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0xFF00) | val; break; + case 0x7f9b: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00FF) | (val << 8); break; + case 0x7f9c: et4000->acl.queued.ctrl_routing = val; break; + case 0x7f9d: et4000->acl.queued.ctrl_reload = val; break; + case 0x7f9e: et4000->acl.queued.rop_bg = val; break; + case 0x7f9f: et4000->acl.queued.rop_fg = val; break; + case 0x7fa0: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFFFF00) | val; break; + case 0x7fa1: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7fa2: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7fa3: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00FFFFFF) | (val << 24); + et4000->acl.internal = et4000->acl.queued; + et4000w32_blit_start(et4000); + if (!(et4000->acl.queued.ctrl_routing & 0x43)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0, et4000); + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32_blit(4, ~0, 0, 0, et4000); + break; + case 0x7fa4: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFFFF00) | val; break; + case 0x7fa5: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7fa6: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7fa7: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7fa8: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0xFF00) | val; break; + case 0x7fa9: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0x00FF) | (val << 8); break; + case 0x7faa: et4000->acl.queued.error = (et4000->acl.queued.error & 0xFF00) | val; break; + case 0x7fab: et4000->acl.queued.error = (et4000->acl.queued.error & 0x00FF) | (val << 8); break; + case 0x7fac: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0xFF00) | val; break; + case 0x7fad: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0x00FF) | (val << 8); break; + case 0x7fae: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0xFF00) | val; break; + case 0x7faf: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0x00FF) | (val << 8); break; + } +} + +static void et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + if (!(et4000->acl.status & ACL_XYST)) return; + if (et4000->acl.internal.ctrl_routing & 3) + { + if ((et4000->acl.internal.ctrl_routing & 3) == 2) + { + if (et4000->acl.mix_addr & 7) + et4000w32_blit(8 - (et4000->acl.mix_addr & 7), val >> (et4000->acl.mix_addr & 7), 0, 1, et4000); + else + et4000w32_blit(8, val, 0, 1, et4000); + } + else if ((et4000->acl.internal.ctrl_routing & 3) == 1) + et4000w32_blit(1, ~0, val, 2, et4000); + } +} + +static void fifo_thread(void *param) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)param; + + while (1) + { + thread_set_event(et4000->fifo_not_full_event); + thread_wait_event(et4000->wake_fifo_thread, -1); + thread_reset_event(et4000->wake_fifo_thread); + et4000->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &et4000->fifo[et4000->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + et4000w32p_accel_write_fifo(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_MMU: + et4000w32p_accel_write_mmu(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + et4000->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(et4000->fifo_not_full_event); + + end_time = timer_read(); + et4000->blitter_time += end_time - start_time; + } + et4000->blitter_busy = 0; + } +} + +static inline void wake_fifo_thread(et4000w32p_t *et4000) +{ + thread_set_event(et4000->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void et4000w32p_wait_fifo_idle(et4000w32p_t *et4000) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(et4000); + thread_wait_event(et4000->fifo_not_full_event, 1); + } +} + +static void et4000w32p_queue(et4000w32p_t *et4000, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &et4000->fifo[et4000->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(et4000->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(et4000->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + et4000->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(et4000); +} + +void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + int bank; +// pclog("ET4K write %08X %02X %02X %04X(%08X):%08X\n",addr,val,et4000->acl.status,et4000->acl.internal.ctrl_routing,CS,cs,pc); +// et4000->acl.status |= ACL_RDST; + switch (addr & 0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << bank)) + { + et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_MMU); + } + else + { + if ((addr&0x1fff) + et4000->mmu.base[bank] < svga->vram_limit) + { + svga->vram[(addr & 0x1fff) + et4000->mmu.base[bank]] = val; + svga->changedvram[((addr & 0x1fff) + et4000->mmu.base[bank]) >> 12] = changeframecount; + } + } + break; + case 0x6000: + if ((addr & 0x7fff) >= 0x7f80) + { + et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0x7fff) + { + case 0x7f00: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFFFF00) | val; break; + case 0x7f01: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFF00FF) | (val << 8); break; + case 0x7f02: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFF00FFFF) | (val << 16); break; + case 0x7f03: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x00FFFFFF) | (val << 24); break; + case 0x7f04: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFFFF00) | val; break; + case 0x7f05: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFF00FF) | (val << 8); break; + case 0x7f06: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFF00FFFF) | (val << 16); break; + case 0x7f07: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x00FFFFFF) | (val << 24); break; + case 0x7f08: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFFFF00) | val; break; + case 0x7f09: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFF00FF) | (val << 8); break; + case 0x7f0a: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFF00FFFF) | (val << 16); break; + case 0x7f0d: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x00FFFFFF) | (val << 24); break; + case 0x7f13: et4000->mmu.ctrl=val; break; + } + break; + } +} + +uint8_t et4000w32p_mmu_read(uint32_t addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + int bank; + uint8_t temp; +// pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); + switch (addr & 0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << bank)) + { + et4000w32p_wait_fifo_idle(et4000); + temp = 0xff; + if (et4000->acl.cpu_dat_pos) + { + et4000->acl.cpu_dat_pos--; + temp = et4000->acl.cpu_dat & 0xff; + et4000->acl.cpu_dat >>= 8; + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !et4000->acl.cpu_dat_pos && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32_blit(4, ~0, 0, 0, et4000); + /*???*/ + return temp; + } + if ((addr&0x1fff) + et4000->mmu.base[bank] >= svga->vram_limit) + return 0xff; + return svga->vram[(addr&0x1fff) + et4000->mmu.base[bank]]; + + case 0x6000: + if ((addr & 0x7fff) >= 0x7f80) + et4000w32p_wait_fifo_idle(et4000); + switch (addr&0x7fff) + { + case 0x7f00: return et4000->mmu.base[0]; + case 0x7f01: return et4000->mmu.base[0] >> 8; + case 0x7f02: return et4000->mmu.base[0] >> 16; + case 0x7f03: return et4000->mmu.base[0] >> 24; + case 0x7f04: return et4000->mmu.base[1]; + case 0x7f05: return et4000->mmu.base[1] >> 8; + case 0x7f06: return et4000->mmu.base[1] >> 16; + case 0x7f07: return et4000->mmu.base[1] >> 24; + case 0x7f08: return et4000->mmu.base[2]; + case 0x7f09: return et4000->mmu.base[2] >> 8; + case 0x7f0a: return et4000->mmu.base[2] >> 16; + case 0x7f0b: return et4000->mmu.base[2] >> 24; + case 0x7f13: return et4000->mmu.ctrl; + + case 0x7f36: + temp = et4000->acl.status; +// et4000->acl.status &= ~ACL_RDST; + temp &= ~0x03; + if (!FIFO_EMPTY) + temp |= 0x02; + if (FIFO_FULL) + temp |= 0x01; +// if (et4000->acl.internal.pos_x!=et4000->acl.internal.count_x || et4000->acl.internal.pos_y!=et4000->acl.internal.count_y) return et4000->acl.status | ACL_XYST; + return temp; + case 0x7f80: return et4000->acl.internal.pattern_addr; + case 0x7f81: return et4000->acl.internal.pattern_addr >> 8; + case 0x7f82: return et4000->acl.internal.pattern_addr >> 16; + case 0x7f83: return et4000->acl.internal.pattern_addr >> 24; + case 0x7f84: return et4000->acl.internal.source_addr; + case 0x7f85: return et4000->acl.internal.source_addr >> 8; + case 0x7f86: return et4000->acl.internal.source_addr >> 16; + case 0x7f87: return et4000->acl.internal.source_addr >> 24; + case 0x7f88: return et4000->acl.internal.pattern_off; + case 0x7f89: return et4000->acl.internal.pattern_off >> 8; + case 0x7f8a: return et4000->acl.internal.source_off; + case 0x7f8b: return et4000->acl.internal.source_off >> 8; + case 0x7f8c: return et4000->acl.internal.dest_off; + case 0x7f8d: return et4000->acl.internal.dest_off >> 8; + case 0x7f8e: return et4000->acl.internal.pixel_depth; + case 0x7f8f: return et4000->acl.internal.xy_dir; + case 0x7f90: return et4000->acl.internal.pattern_wrap; + case 0x7f92: return et4000->acl.internal.source_wrap; + case 0x7f98: return et4000->acl.internal.count_x; + case 0x7f99: return et4000->acl.internal.count_x >> 8; + case 0x7f9a: return et4000->acl.internal.count_y; + case 0x7f9b: return et4000->acl.internal.count_y >> 8; + case 0x7f9c: return et4000->acl.internal.ctrl_routing; + case 0x7f9d: return et4000->acl.internal.ctrl_reload; + case 0x7f9e: return et4000->acl.internal.rop_bg; + case 0x7f9f: return et4000->acl.internal.rop_fg; + case 0x7fa0: return et4000->acl.internal.dest_addr; + case 0x7fa1: return et4000->acl.internal.dest_addr >> 8; + case 0x7fa2: return et4000->acl.internal.dest_addr >> 16; + case 0x7fa3: return et4000->acl.internal.dest_addr >> 24; + } + return 0xff; + } + return 0xff; +} + +static int et4000w32_max_x[8]={0,0,4,8,16,32,64,0x70000000}; +static int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +static int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +int bltout=0; +void et4000w32_blit_start(et4000w32p_t *et4000) +{ +// if (et4000->acl.queued.xy_dir&0x80) +// pclog("Blit - %02X %08X (%i,%i) %08X (%i,%i) %08X (%i,%i) %i %i %i %02X %02X %02X\n",et4000->acl.queued.xy_dir,et4000->acl.internal.pattern_addr,(et4000->acl.internal.pattern_addr/3)%640,(et4000->acl.internal.pattern_addr/3)/640,et4000->acl.internal.source_addr,(et4000->acl.internal.source_addr/3)%640,(et4000->acl.internal.source_addr/3)/640,et4000->acl.internal.dest_addr,(et4000->acl.internal.dest_addr/3)%640,(et4000->acl.internal.dest_addr/3)/640,et4000->acl.internal.xy_dir,et4000->acl.internal.count_x,et4000->acl.internal.count_y,et4000->acl.internal.rop_fg,et4000->acl.internal.rop_bg, et4000->acl.internal.ctrl_routing); +// bltout=1; +// bltout=(et4000->acl.internal.count_x==1541); + if (!(et4000->acl.queued.xy_dir & 0x20)) + et4000->acl.internal.error = et4000->acl.internal.dmaj / 2; + et4000->acl.pattern_addr= et4000->acl.internal.pattern_addr; + et4000->acl.source_addr = et4000->acl.internal.source_addr; + et4000->acl.mix_addr = et4000->acl.internal.mix_addr; + et4000->acl.mix_back = et4000->acl.mix_addr; + et4000->acl.dest_addr = et4000->acl.internal.dest_addr; + et4000->acl.dest_back = et4000->acl.dest_addr; + et4000->acl.internal.pos_x = et4000->acl.internal.pos_y = 0; + et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0; + et4000->acl.status |= ACL_XYST; + if ((!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) && !(et4000->acl.internal.ctrl_routing & 0x40)) + et4000->acl.status |= ACL_SSO; + + if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) + { + et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + } + et4000->acl.pattern_back = et4000->acl.pattern_addr; + if (!(et4000->acl.internal.pattern_wrap & 0x40)) + { + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); + } + et4000->acl.pattern_x_back = et4000->acl.pattern_x; + + if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) + { + et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + } + et4000->acl.source_back = et4000->acl.source_addr; + if (!(et4000->acl.internal.source_wrap & 0x40)) + { + et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); + } + et4000->acl.source_x_back = et4000->acl.source_x; + + et4000w32_max_x[2] = ((et4000->acl.internal.pixel_depth & 0x30) == 0x20) ? 3 : 4; + + et4000->acl.internal.count_x += (et4000->acl.internal.pixel_depth >> 4) & 3; + et4000->acl.cpu_dat_pos = 0; + et4000->acl.cpu_dat = 0; + + et4000->acl.pix_pos = 0; +} + +void et4000w32_incx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr += c; + et4000->acl.pattern_x += c; + et4000->acl.source_x += c; + et4000->acl.mix_addr += c; + if (et4000->acl.pattern_x >= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]) + et4000->acl.pattern_x -= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x >= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]) + et4000->acl.source_x -= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} +void et4000w32_decx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr -= c; + et4000->acl.pattern_x -= c; + et4000->acl.source_x -= c; + et4000->acl.mix_addr -= c; + if (et4000->acl.pattern_x < 0) + et4000->acl.pattern_x += et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x < 0) + et4000->acl.source_x += et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} +void et4000w32_incy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr += et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr += et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr += et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr += et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y++; + if (et4000->acl.pattern_y == et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) + { + et4000->acl.pattern_y = 0; + et4000->acl.pattern_addr = et4000->acl.pattern_back; + } + et4000->acl.source_y++; + if (et4000->acl.source_y == et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) + { + et4000->acl.source_y = 0; + et4000->acl.source_addr = et4000->acl.source_back; + } +} +void et4000w32_decy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr -= et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr -= et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr -= et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr -= et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y--; + if (et4000->acl.pattern_y < 0 && !(et4000->acl.internal.pattern_wrap & 0x40)) + { + et4000->acl.pattern_y = et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1; + et4000->acl.pattern_addr = et4000->acl.pattern_back + (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1)); + } + et4000->acl.source_y--; + if (et4000->acl.source_y < 0 && !(et4000->acl.internal.source_wrap & 0x40)) + { + et4000->acl.source_y = et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1; + et4000->acl.source_addr = et4000->acl.source_back + (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] *(et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1));; + } +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + int c,d; + uint8_t pattern, source, dest, out; + uint8_t rop; + int mixdat; + + if (!(et4000->acl.status & ACL_XYST)) return; +// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",et4000->acl.internal.count_x,et4000->acl.internal.count_y,et4000->acl.dest_addr,et4000->acl.dest_addr%640,et4000->acl.dest_addr/640,et4000->acl.source_addr,et4000->acl.pattern_addr); + //pclog("Blit exec - %i %i %i\n",count,et4000->acl.internal.pos_x,et4000->acl.internal.pos_y); + if (et4000->acl.internal.xy_dir & 0x80) /*Line draw*/ + { + while (count--) + { + if (bltout) pclog("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; + if (bltout) pclog("%06X %06X ", (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff); + if (cpu_input == 2) + { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; + out = 0; + if (bltout) pclog("%06X ", et4000->acl.dest_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) + { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); + if (bltout) pclog("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); + } + else + { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + et4000->acl.mix_addr++; + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + for (c = 0; c < 8; c++) + { + d = (dest & (1 << c)) ? 1 : 0; + if (source & (1 << c)) d |= 2; + if (pattern & (1 << c)) d |= 4; + if (rop & (1 << d)) out |= (1 << c); + } + if (bltout) pclog("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) + { + svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; + svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; + } + else + { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + +// pclog("%i %i\n",et4000->acl.pix_pos,(et4000->acl.internal.pixel_depth>>4)&3); + et4000->acl.pix_pos++; + et4000->acl.internal.pos_x++; + if (et4000->acl.pix_pos <= ((et4000->acl.internal.pixel_depth >> 4) & 3)) + { + if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); + else et4000w32_incx(1, et4000); + } + else + { + if (et4000->acl.internal.xy_dir & 1) + et4000w32_incx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + else + et4000w32_decx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + et4000->acl.pix_pos = 0; + /*Next pixel*/ + switch (et4000->acl.internal.xy_dir & 7) + { + case 0: case 1: /*Y+*/ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 2: case 3: /*Y-*/ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 4: case 6: /*X+*/ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + //et4000->acl.internal.pos_x++; + break; + case 5: case 7: /*X-*/ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + //et4000->acl.internal.pos_x++; + break; + } + et4000->acl.internal.error += et4000->acl.internal.dmin; + if (et4000->acl.internal.error > et4000->acl.internal.dmaj) + { + et4000->acl.internal.error -= et4000->acl.internal.dmaj; + switch (et4000->acl.internal.xy_dir & 7) + { + case 0: case 2: /*X+*/ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 1: case 3: /*X-*/ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 4: case 5: /*Y+*/ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + break; + case 6: case 7: /*Y-*/ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + break; + } + } + if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x || + et4000->acl.internal.pos_y > et4000->acl.internal.count_y) + { + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); +// pclog("Blit line over\n"); + return; + } + } + } + } + else + { + while (count--) + { + if (bltout) pclog("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; + if (bltout) pclog("%i %06X %06X %02X %02X ", et4000->acl.pattern_y, (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff, pattern, source); + + if (cpu_input == 2) + { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; + out = 0; + if (bltout) pclog("%06X %02X %i %08X %08X ", dest, et4000->acl.dest_addr, mix & 1, mix, et4000->acl.mix_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) + { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); + if (bltout) pclog("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); + } + else + { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + for (c = 0; c < 8; c++) + { + d = (dest & (1 << c)) ? 1 : 0; + if (source & (1 << c)) d |= 2; + if (pattern & (1 << c)) d |= 4; + if (rop & (1 << d)) out |= (1 << c); + } + if (bltout) pclog("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) + { + svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; + svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; + } + else + { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + + if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); + else et4000w32_incx(1, et4000); + + et4000->acl.internal.pos_x++; + if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x) + { + if (et4000->acl.internal.xy_dir & 2) + { + et4000w32_decy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back - (et4000->acl.internal.mix_off + 1); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } + else + { + et4000w32_incy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back + et4000->acl.internal.mix_off + 1; + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; + } + + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; + + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x = 0; + if (et4000->acl.internal.pos_y > et4000->acl.internal.count_y) + { + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); +// pclog("Blit over\n"); + return; + } + if (cpu_input) return; + if (et4000->acl.internal.ctrl_routing & 0x40) + { + if (et4000->acl.cpu_dat_pos & 3) + et4000->acl.cpu_dat_pos += 4 - (et4000->acl.cpu_dat_pos & 3); + return; + } + } + } + } +} + + +void et4000w32p_hwcursor_draw(svga_t *svga, int displine) +{ + int x, offset; + uint8_t dat; + offset = svga->hwcursor_latch.xoff; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) + { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga->hwcursor_latch.addr += 16; +} + +static void et4000w32p_io_remove(et4000w32p_t *et4000) +{ + io_removehandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_removehandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +static void et4000w32p_io_set(et4000w32p_t *et4000) +{ + et4000w32p_io_remove(et4000); + + io_sethandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_sethandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +uint8_t et4000w32p_pci_read(int func, int addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + +// pclog("ET4000 PCI read %08X\n", addr); + + switch (addr) + { + case 0x00: return 0x0c; /*Tseng Labs*/ + case 0x01: return 0x10; + + case 0x02: return 0x06; /*ET4000W32p Rev D*/ + case 0x03: return 0x32; + + case PCI_REG_COMMAND: + return et4000->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return svga->crtc[0x5a] & 0x80; + case 0x13: return svga->crtc[0x59]; + + case 0x30: return et4000->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return et4000->pci_regs[0x32]; + case 0x33: return et4000->pci_regs[0x33]; + } + return 0; +} + +void et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + switch (addr) + { + case PCI_REG_COMMAND: + if (romset == ROM_KN97) return; + et4000->pci_regs[PCI_REG_COMMAND] = val & 0x27; + if (val & PCI_COMMAND_IO) + et4000w32p_io_set(et4000); + else + et4000w32p_io_remove(et4000); + et4000w32p_recalcmapping(et4000); + break; + + case 0x13: + et4000->linearbase = val << 24; + et4000w32p_recalcmapping(et4000); + break; + + case 0x30: case 0x32: case 0x33: + et4000->pci_regs[addr] = val; + if (et4000->pci_regs[0x30] & 0x01) + { + uint32_t addr = (et4000->pci_regs[0x32] << 16) | (et4000->pci_regs[0x33] << 24); + // pclog("ET4000 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&et4000->bios_rom.mapping, addr, 0x8000); + } + else + { + // pclog("ET4000 bios_rom disabled\n"); + mem_mapping_disable(&et4000->bios_rom.mapping); + } + return; + } +} + +void *et4000w32p_common_init(char *biosfile) +{ + int vram_size; + int bios_offset = 0; + int checksum_diff = 0; + et4000w32p_t *et4000 = malloc(sizeof(et4000w32p_t)); + memset(et4000, 0, sizeof(et4000w32p_t)); + + vram_size = device_get_config_int("memory"); + et4000->vram_size = vram_size; + + et4000->revision = device_get_config_int("revision"); + + et4000->interleaved = (vram_size == 2) ? 1 : 0; + + et4000->max_ram_mask = (gfxcard == GFX_ET4000W32) ? 0x1fffff : 0x3fffff; + // et4000->max_ram_mask = 0x1fffff; + + svga_init(&et4000->svga, et4000, vram_size << 20, + et4000w32p_recalctimings, + et4000w32p_in, et4000w32p_out, + et4000w32p_hwcursor_draw, + NULL); + + rom_init(&et4000->bios_rom, biosfile, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (vram_size == 4) + { + /* The ROM is hardcoded to 256k sticks, so let's patch it for 1M. */ + if (memcmp(&((&et4000->bios_rom)->rom[0x008f]), "04/28/95 V2.10N", 15) == 0) + { + bios_offset = 0x0244; + } + if (memcmp(&((&et4000->bios_rom)->rom[0x008f]), "05/15/95 V8.00N", 15) == 0) + { + bios_offset = 0x027f; + } + if (bios_offset) + { + checksum_diff = (&et4000->bios_rom)->rom[bios_offset] - 0x03; + if (checksum_diff) + { + (&et4000->bios_rom)->rom[bios_offset] = 0x03; + (&et4000->bios_rom)->rom[0x7fff] += checksum_diff; + pclog("BIOS patched: %08X: %02X 03\n", bios_offset, checksum_diff + 0x03); + } + } + else + { + pclog("No known BIOS detected or BIOS already set to 1 MB DRAM modules, maximum VRAM is 2 MB\n"); + vram_size == 2; + } + } + if (PCI) + mem_mapping_disable(&et4000->bios_rom.mapping); + + mem_mapping_add(&et4000->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &et4000->svga); + mem_mapping_add(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, 0, et4000); + + et4000w32p_io_set(et4000); + + pci_add(et4000w32p_pci_read, et4000w32p_pci_write, et4000); + + et4000->pci_regs[0x04] = 7; + + et4000->pci_regs[0x30] = 0x00; + et4000->pci_regs[0x32] = 0x0c; + et4000->pci_regs[0x33] = 0x00; + + et4000->wake_fifo_thread = thread_create_event(); + et4000->fifo_not_full_event = thread_create_event(); + et4000->fifo_thread = thread_create(fifo_thread, et4000); + + return et4000; +} + +void *et4000w32p_init() +{ + return et4000w32p_common_init("roms/et4000w32.bin"); +} + +void *et4000w32pc_init() +{ + return et4000w32p_common_init("roms/cardex.vbi"); +} + +int et4000w32p_available() +{ + return rom_present("roms/et4000w32.bin"); +} + +int et4000w32pc_available() +{ + return rom_present("roms/cardex.vbi"); +} + +void et4000w32p_close(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_close(&et4000->svga); + + free(et4000); +} + +void et4000w32p_speed_changed(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_recalctimings(&et4000->svga); +} + +void et4000w32p_force_redraw(void *p) +{ + et4000w32p_t *et4000w32p = (et4000w32p_t *)p; + + et4000w32p->svga.fullchange = changeframecount; +} + +void et4000w32p_add_status_info(char *s, int max_len, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - et4000->status_time; + et4000->status_time = new_time; + + svga_add_status_info(s, max_len, &et4000->svga); + + sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)et4000->blitter_time * 100.0) / timer_freq, ((double)et4000->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + et4000->blitter_time = 0; +} + +static device_config_t et4000w32p_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "revision", + .description = "Revision", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Rev. A", + .value = 2 + }, + { + .description = "Rev. B", + .value = 5 + }, + { + .description = "Rev. D", + .value = 6 + }, + { + .description = "Rev. C", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 6 + }, + { + .type = -1 + } +}; + +static device_config_t et4000w32pc_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "revision", + .description = "Revision", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Rev. A", + .value = 2 + }, + { + .description = "Rev. B", + .value = 5 + }, + { + .description = "Rev. D", + .value = 6 + }, + { + .description = "Rev. C", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 6 + }, + { + .type = -1 + } +}; + +device_t et4000w32p_device = +{ + "Tseng Labs ET4000/w32p", + 0, + et4000w32p_init, + et4000w32p_close, + et4000w32p_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_add_status_info, + et4000w32p_config +}; + +device_t et4000w32pc_device = +{ + "Cardex Tseng Labs ET4000/w32p", + 0, + et4000w32pc_init, + et4000w32p_close, + et4000w32pc_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_add_status_info, + et4000w32pc_config +}; diff --git a/src/vid_et4000w32.h b/src/vid_et4000w32.h new file mode 100644 index 000000000..1b91ff09d --- /dev/null +++ b/src/vid_et4000w32.h @@ -0,0 +1,2 @@ +extern device_t et4000w32p_device; +extern device_t et4000w32pc_device; diff --git a/src/vid_et4000w32i.c b/src/vid_et4000w32i.c new file mode 100644 index 000000000..5aec84b1f --- /dev/null +++ b/src/vid_et4000w32i.c @@ -0,0 +1,407 @@ +/*The below is (with some removals) a reasonable emulation of the ET4000/W32i blitter. + Unfortunately the Diamond Stealth 32 is actually an ET4000/W32p! Which has a different + blitter. If only I'd dug out and looked at the card before trying to emulate it. + + This might be of use for an attempt at emulating an ET4000/W32i. + */ +#if 0 + +#include "ibm.h" + +int et4k_b8000; + +struct +{ + struct + { + uint32_t pattern_addr,source_addr,dest_addr; + uint16_t pattern_off,source_off,dest_off; + uint8_t vbus,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr; + uint32_t pattern_back,dest_back; + int pattern_x,source_x; + int pattern_x_back; + int pattern_y,source_y; + uint8_t status; + uint32_t cpu_input; + int cpu_input_num; +} acl; + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +struct +{ + uint32_t base[3]; + uint8_t ctrl; +} mmu; + +void et4000w32_reset() +{ + acl.status=0; + acl.cpu_input_num=0; +} + +void et4000w32_blit_start(); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input); + +int et4000w32_vbus[4]={1,2,4,4}; + +void et4000w32_mmu_write(uint32_t addr, uint8_t val) +{ + int bank; + pclog("ET4K write %08X %02X %i %02X %02X %04X(%08X):%08X %04X %04X %02X %08X\n",addr,val,acl.cpu_input_num,acl.status,acl.internal.ctrl_routing,CS,cs,pc,CS,DI,mmu.ctrl,mmu.base[2]); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>12]=changeframecount; + } + break; + case 0x6000: + switch (addr&0x7FFF) + { + case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break; + case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break; + case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break; + case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break; + case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break; + case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break; + case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break; + case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break; + case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break; + case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break; + case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break; + case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break; + case 0x7F13: mmu.ctrl=val; break; + + case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break; + case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break; + case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break; + case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break; + case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break; + case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break; + case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break; + case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break; + case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break; + case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break; + case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break; + case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break; + case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break; + case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break; + case 0x7F8E: acl.queued.vbus=val; break; + case 0x7F8F: acl.queued.xy_dir=val; break; + case 0x7F90: acl.queued.pattern_wrap=val; break; + case 0x7F92: acl.queued.source_wrap=val; break; + case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break; + case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break; + case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break; + case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break; + case 0x7F9C: acl.queued.ctrl_routing=val; break; + case 0x7F9D: acl.queued.ctrl_reload =val; break; + case 0x7F9E: acl.queued.rop_bg =val; break; + case 0x7F9F: acl.queued.rop_fg =val; break; + case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break; + case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break; + case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break; + case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24); + acl.internal=acl.queued; + et4000w32_blit_start(); + acl.cpu_input_num=0; + if (!(acl.queued.ctrl_routing&0x37)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0); + } + break; + } + break; + } +} + +uint8_t et4000w32_mmu_read(uint32_t addr) +{ + int bank; + pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>8; + case 0x7F02: return mmu.base[0]>>16; + case 0x7F03: return mmu.base[0]>>24; + case 0x7F04: return mmu.base[1]; + case 0x7F05: return mmu.base[1]>>8; + case 0x7F06: return mmu.base[1]>>16; + case 0x7F07: return mmu.base[1]>>24; + case 0x7F08: return mmu.base[2]; + case 0x7F09: return mmu.base[2]>>8; + case 0x7F0A: return mmu.base[2]>>16; + case 0x7F0B: return mmu.base[2]>>24; + case 0x7F13: return mmu.ctrl; + + case 0x7F36: +// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST; + return acl.status & ~(ACL_XYST | ACL_SSO); + case 0x7F80: return acl.internal.pattern_addr; + case 0x7F81: return acl.internal.pattern_addr>>8; + case 0x7F82: return acl.internal.pattern_addr>>16; + case 0x7F83: return acl.internal.pattern_addr>>24; + case 0x7F84: return acl.internal.source_addr; + case 0x7F85: return acl.internal.source_addr>>8; + case 0x7F86: return acl.internal.source_addr>>16; + case 0x7F87: return acl.internal.source_addr>>24; + case 0x7F88: return acl.internal.pattern_off; + case 0x7F89: return acl.internal.pattern_off>>8; + case 0x7F8A: return acl.internal.source_off; + case 0x7F8B: return acl.internal.source_off>>8; + case 0x7F8C: return acl.internal.dest_off; + case 0x7F8D: return acl.internal.dest_off>>8; + case 0x7F8E: return acl.internal.vbus; + case 0x7F8F: return acl.internal.xy_dir; + case 0x7F90: return acl.internal.pattern_wrap; + case 0x7F92: return acl.internal.source_wrap; + case 0x7F98: return acl.internal.count_x; + case 0x7F99: return acl.internal.count_x>>8; + case 0x7F9A: return acl.internal.count_y; + case 0x7F9B: return acl.internal.count_y>>8; + case 0x7F9C: return acl.internal.ctrl_routing; + case 0x7F9D: return acl.internal.ctrl_reload; + case 0x7F9E: return acl.internal.rop_bg; + case 0x7F9F: return acl.internal.rop_fg; + case 0x7FA0: return acl.internal.dest_addr; + case 0x7FA1: return acl.internal.dest_addr>>8; + case 0x7FA2: return acl.internal.dest_addr>>16; + case 0x7FA3: return acl.internal.dest_addr>>24; + } + return 0xFF; + } +} + +int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +void et4000w32_blit_start() +{ + pclog("Blit - %08X %08X %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.internal.pattern_addr,acl.internal.source_addr,acl.internal.dest_addr,acl.internal.dest_addr%640,acl.internal.dest_addr/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing); + acl.pattern_addr=acl.internal.pattern_addr; + acl.source_addr =acl.internal.source_addr; + acl.dest_addr =acl.internal.dest_addr; + acl.dest_back =acl.dest_addr; + acl.internal.pos_x=acl.internal.pos_y=0; + acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0; + acl.status = ACL_XYST; + if (!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) acl.status |= ACL_SSO; + if (et4000w32_wrap_x[acl.internal.pattern_wrap&7]) + { + acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + } + if (!(acl.internal.pattern_wrap&0x80)) + { + acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1); + acl.pattern_addr&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1); + } + acl.pattern_x_back=acl.pattern_x; + acl.pattern_back=acl.pattern_addr; +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input) +{ + int c,d; + uint8_t pattern,source,dest,out; + uint8_t rop; + +// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr); +// pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y); + while (count--) + { + pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y); + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr-acl.pattern_x)&0x1FFFFF,(acl.source_addr -acl.source_x) &0x1FFFFF); + } + else + { + pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF); + } + if (cpu_input==2) + { + source=sdat&0xFF; + sdat>>=8; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + pclog("%06X %i %08X ",acl.dest_addr,mix&1,mix); + rop = (mix & 1) ? acl.internal.rop_fg:acl.internal.rop_bg; + mix>>=1; mix|=0x80000000; + for (c=0;c<8;c++) + { + d=(dest & (1<>12]=changeframecount; + + acl.pattern_x++; + acl.pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.source_x++; + acl.source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + + acl.internal.pos_x++; + if (acl.internal.pos_x>acl.internal.count_x) + { + if (acl.internal.xy_dir&2) + { + acl.pattern_addr-=(acl.internal.pattern_off+1); + acl.source_addr -=(acl.internal.source_off +1); + acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1); + } + else + { + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off +1; + acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1; + } + acl.pattern_x = acl.pattern_x_back; + acl.source_x = 0; + acl.pattern_y++; + if (acl.pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + acl.pattern_y=0; + acl.pattern_addr=acl.pattern_back; + } + acl.source_y++; + if (acl.source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + acl.source_y=0; + acl.source_addr=acl.internal.source_addr; + } + + acl.internal.pos_y++; + if (acl.internal.pos_y>acl.internal.count_y) + { + acl.status = 0; + return; + } + acl.internal.pos_x=0; + if (cpu_input) return; + } + } +} + +/* for (y=0;y<=acl.internal.count_y;y++) + { + dest_back=acl.dest_addr; + for (x=0;x<=acl.internal.count_x;x++) + { + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -source_x) &0x1FFFFF]; + } + else + { + pattern=vram[(acl.pattern_addr+pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +source_x) &0x1FFFFF]; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + for (c=0;c<8;c++) + { + d=(dest&(1<>12]=changeframecount; + + pattern_x++; + pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + source_x++; + source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + } + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off+1; + acl.dest_addr=dest_back+acl.internal.dest_off+1; + pattern_y++; + if (pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + pattern_y=0; + acl.pattern_addr=acl.internal.pattern_addr; + } + source_y++; + if (source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + source_y=0; + acl.source_addr=acl.internal.source_addr; + } + }*/ + +#endif diff --git a/src/vid_hercules.c b/src/vid_hercules.c new file mode 100644 index 000000000..c834f55bb --- /dev/null +++ b/src/vid_hercules.c @@ -0,0 +1,371 @@ +/*Hercules emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_hercules.h" + +typedef struct hercules_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int dispontime, dispofftime; + int vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int vsynctime, vadj; + + uint8_t *vram; +} hercules_t; + +static int mdacols[256][2][2]; + +void hercules_recalctimings(hercules_t *hercules); +void hercules_write(uint32_t addr, uint8_t val, void *p); +uint8_t hercules_read(uint32_t addr, void *p); + + +void hercules_out(uint16_t addr, uint8_t val, void *p) +{ + hercules_t *hercules = (hercules_t *)p; +// pclog("Herc out %04X %02X\n",addr,val); + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + hercules->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + hercules->crtc[hercules->crtcreg] = val; + if (hercules->crtc[10] == 6 && hercules->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + hercules->crtc[10] = 0xb; + hercules->crtc[11] = 0xc; + } + hercules_recalctimings(hercules); + return; + case 0x3b8: + hercules->ctrl = val; + return; + case 0x3bf: + hercules->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t hercules_in(uint16_t addr, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + // pclog("Herc in %04X %02X %04X:%04X %04X\n",addr,(hercules_stat & 0xF) | ((hercules_stat & 8) << 4),CS,pc,CX); + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return hercules->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + return hercules->crtc[hercules->crtcreg]; + case 0x3ba: + return (hercules->stat & 0xf) | ((hercules->stat & 8) << 4); + } + return 0xff; +} + +void hercules_write(uint32_t addr, uint8_t val, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + egawrites++; + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; +// pclog("Herc write %08X %02X\n",addr,val); + hercules->vram[addr & 0xffff] = val; +} + +uint8_t hercules_read(uint32_t addr, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + egareads++; + return hercules->vram[addr & 0xffff]; +} + +void hercules_recalctimings(hercules_t *hercules) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = hercules->crtc[0] + 1; + _dispontime = hercules->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + hercules->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + hercules->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void hercules_poll(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + uint16_t ca = (hercules->crtc[15] | (hercules->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int oldsc; + int blink; + if (!hercules->linepos) + { + //pclog("Poll %i %i\n",vc,sc); + hercules->vidtime += hercules->dispofftime; + hercules->stat |= 1; + hercules->linepos = 1; + oldsc = hercules->sc; + if ((hercules->crtc[8] & 3) == 3) + hercules->sc = (hercules->sc << 1) & 7; + if (hercules->dispon) + { + if (hercules->displine < hercules->firstline) + { + hercules->firstline = hercules->displine; + } + hercules->lastline = hercules->displine; + cols[0] = 0; + cols[1] = 7; + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) + { + ca = (hercules->sc & 3) * 0x2000; + if ((hercules->ctrl & 0x80) && (hercules->ctrl2 & 2)) + ca += 0x8000; +// printf("Draw herc %04X\n",ca); + for (x = 0; x < hercules->crtc[1]; x++) + { + dat = (hercules->vram[((hercules->ma << 1) & 0x1fff) + ca] << 8) | hercules->vram[((hercules->ma << 1) & 0x1fff) + ca + 1]; + hercules->ma++; + for (c = 0; c < 16; c++) + buffer->line[hercules->displine][(x << 4) + c] = (dat & (32768 >> c)) ? 7 : 0; + } + } + else + { + for (x = 0; x < hercules->crtc[1]; x++) + { + chr = hercules->vram[(hercules->ma << 1) & 0x3fff]; + attr = hercules->vram[((hercules->ma << 1) + 1) & 0x3fff]; + drawcursor = ((hercules->ma == ca) && hercules->con && hercules->cursoron); + blink = ((hercules->blink & 16) && (hercules->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + if (hercules->sc == 12 && ((attr & 7) == 1)) + { + for (c = 0; c < 9; c++) + buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][1]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][hercules->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][hercules->sc] & 1]; + else buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + } + hercules->ma++; + if (drawcursor) + { + for (c = 0; c < 9; c++) + buffer->line[hercules->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + } + } + } + } + hercules->sc = oldsc; + if (hercules->vc == hercules->crtc[7] && !hercules->sc) + { + hercules->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + hercules->displine++; + if (hercules->displine >= 500) + hercules->displine = 0; + } + else + { + hercules->vidtime += hercules->dispontime; + if (hercules->dispon) + hercules->stat &= ~1; + hercules->linepos = 0; + if (hercules->vsynctime) + { + hercules->vsynctime--; + if (!hercules->vsynctime) + { + hercules->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (hercules->sc == (hercules->crtc[11] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[11] & 31) >> 1))) + { + hercules->con = 0; + hercules->coff = 1; + } + if (hercules->vadj) + { + hercules->sc++; + hercules->sc &= 31; + hercules->ma = hercules->maback; + hercules->vadj--; + if (!hercules->vadj) + { + hercules->dispon = 1; + hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; + hercules->sc = 0; + } + } + else if (hercules->sc == hercules->crtc[9] || ((hercules->crtc[8] & 3) == 3 && hercules->sc == (hercules->crtc[9] >> 1))) + { + hercules->maback = hercules->ma; + hercules->sc = 0; + oldvc = hercules->vc; + hercules->vc++; + hercules->vc &= 127; + if (hercules->vc == hercules->crtc[6]) + hercules->dispon = 0; + if (oldvc == hercules->crtc[4]) + { +// printf("Display over at %i\n",displine); + hercules->vc = 0; + hercules->vadj = hercules->crtc[5]; + if (!hercules->vadj) hercules->dispon=1; + if (!hercules->vadj) hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; + if ((hercules->crtc[10] & 0x60) == 0x20) hercules->cursoron = 0; + else hercules->cursoron = hercules->blink & 16; + } + if (hercules->vc == hercules->crtc[7]) + { + hercules->dispon = 0; + hercules->displine = 0; + hercules->vsynctime = 16;//(crtcm[3]>>4)+1; + if (hercules->crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) x = hercules->crtc[1] << 4; + else x = hercules->crtc[1] * 9; + hercules->lastline++; + if (x != xsize || (hercules->lastline - hercules->firstline) != ysize) + { + xsize = x; + ysize = hercules->lastline - hercules->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + startblit(); + video_blit_memtoscreen_8(0, hercules->firstline, xsize, ysize); + endblit(); + frames++; + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) + { + video_res_x = hercules->crtc[1] * 16; + video_res_y = hercules->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = hercules->crtc[1]; + video_res_y = hercules->crtc[6]; + video_bpp = 0; + } + } + hercules->firstline = 1000; + hercules->lastline = 0; + hercules->blink++; + } + } + else + { + hercules->sc++; + hercules->sc &= 31; + hercules->ma = hercules->maback; + } + if ((hercules->sc == (hercules->crtc[10] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[10] & 31) >> 1)))) + { + hercules->con = 1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + +void *hercules_init() +{ + int c; + hercules_t *hercules = malloc(sizeof(hercules_t)); + memset(hercules, 0, sizeof(hercules_t)); + + hercules->vram = malloc(0x10000); + + timer_add(hercules_poll, &hercules->vidtime, TIMER_ALWAYS_ENABLED, hercules); + mem_mapping_add(&hercules->mapping, 0xb0000, 0x08000, hercules_read, NULL, NULL, hercules_write, NULL, NULL, NULL, 0, hercules); + io_sethandler(0x03b0, 0x0010, hercules_in, NULL, NULL, hercules_out, NULL, NULL, hercules); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + overscan_x = overscan_y = 0; + + return hercules; +} + +void hercules_close(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + + free(hercules->vram); + free(hercules); +} + +void hercules_speed_changed(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + + hercules_recalctimings(hercules); +} + +device_t hercules_device = +{ + "Hercules", + 0, + hercules_init, + hercules_close, + NULL, + hercules_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_hercules.h b/src/vid_hercules.h new file mode 100644 index 000000000..93b222bc2 --- /dev/null +++ b/src/vid_hercules.h @@ -0,0 +1 @@ +extern device_t hercules_device; diff --git a/src/vid_icd2061.c b/src/vid_icd2061.c new file mode 100644 index 000000000..8dc254ec2 --- /dev/null +++ b/src/vid_icd2061.c @@ -0,0 +1,66 @@ +/*PCem v8.1 by Tom Walker + + ICD2061 clock generator emulation + Used by ET4000w32/p (Diamond Stealth 32)*/ +#include "ibm.h" +#include "vid_icd2061.h" + +void icd2061_write(icd2061_t *icd2061, int val) +{ + int q, p, m, i, a; + if ((val & 1) && !(icd2061->state & 1)) + { + pclog("ICD2061 write %02X %i %08X %i\n", val, icd2061->unlock, icd2061->data, icd2061->pos); + if (!icd2061->status) + { + if (val & 2) + icd2061->unlock++; + else + { + if (icd2061->unlock >= 5) + { + icd2061->status = 1; + icd2061->pos = 0; + } + else + icd2061->unlock = 0; + } + } + else if (val & 1) + { + icd2061->data = (icd2061->data >> 1) | (((val & 2) ? 1 : 0) << 24); + icd2061->pos++; + if (icd2061->pos == 26) + { + pclog("ICD2061 data - %08X\n", icd2061->data); + a = (icd2061->data >> 21) & 0x7; + if (!(a & 4)) + { + q = (icd2061->data & 0x7f) - 2; + m = 1 << ((icd2061->data >> 7) & 0x7); + p = ((icd2061->data >> 10) & 0x7f) - 3; + i = (icd2061->data >> 17) & 0xf; + pclog("p %i q %i m %i\n", p, q, m); + if (icd2061->ctrl & (1 << a)) + p <<= 1; + icd2061->freq[a] = ((double)p / (double)q) * 2.0 * 14318184.0 / (double)m; + pclog("ICD2061 freq %i = %f\n", a, icd2061->freq[a]); + } + else if (a == 6) + { + icd2061->ctrl = val; + pclog("ICD2061 ctrl = %08X\n", val); + } + icd2061->unlock = icd2061->data = 0; + icd2061->status = 0; + } + } + } + icd2061->state = val; +} + +double icd2061_getfreq(icd2061_t *icd2061, int i) +{ + pclog("Return freq %f\n", icd2061->freq[i]); + return icd2061->freq[i]; +} diff --git a/src/vid_icd2061.h b/src/vid_icd2061.h new file mode 100644 index 000000000..6a235fae6 --- /dev/null +++ b/src/vid_icd2061.h @@ -0,0 +1,14 @@ +typedef struct icd2061_t +{ + int state; + int status; + int pos; + int unlock; + uint32_t data; + + double freq[4]; + uint32_t ctrl; +} icd2061_t; + +void icd2061_write(icd2061_t *icd2061, int val); +double icd2061_getfreq(icd2061_t *icd2061, int i); diff --git a/src/vid_ics2595.c b/src/vid_ics2595.c new file mode 100644 index 000000000..72c5b6fdb --- /dev/null +++ b/src/vid_ics2595.c @@ -0,0 +1,55 @@ +/*ICS2595 clock chip emulation + Used by ATI Mach64*/ + +#include "ibm.h" +#include "vid_ics2595.h" + +enum +{ + ICS2595_IDLE = 0, + ICS2595_WRITE, + ICS2595_READ +}; + +static int ics2595_div[4] = {8, 4, 2, 1}; + +void ics2595_write(ics2595_t *ics2595, int strobe, int dat) +{ +// pclog("ics2595_write : %i %i\n", strobe, dat); + if (strobe) + { + if ((dat & 8) && !ics2595->oldfs3) /*Data clock*/ + { +// pclog(" - new dat %i\n", dat & 4); + switch (ics2595->state) + { + case ICS2595_IDLE: + ics2595->state = (dat & 4) ? ICS2595_WRITE : ICS2595_IDLE; + ics2595->pos = 0; + break; + case ICS2595_WRITE: + ics2595->dat = (ics2595->dat >> 1); + if (dat & 4) + ics2595->dat |= (1 << 19); + ics2595->pos++; + if (ics2595->pos == 20) + { + int d, n, l; +// pclog("ICS2595_WRITE : dat %08X\n", ics2595->dat); + l = (ics2595->dat >> 2) & 0xf; + n = ((ics2595->dat >> 7) & 255) + 257; + d = ics2595_div[(ics2595->dat >> 16) & 3]; + + ics2595->clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d; +// pclog("ICS2595 clock set - L %i N %i D %i freq = %f\n", l, n, d, (14318181.8 * ((double)n / 46.0)) / (double)d); + ics2595->state = ICS2595_IDLE; + } + break; + } + } + + ics2595->oldfs2 = dat & 4; + ics2595->oldfs3 = dat & 8; + } + ics2595->output_clock = ics2595->clocks[dat]; +} diff --git a/src/vid_ics2595.h b/src/vid_ics2595.h new file mode 100644 index 000000000..2efe1734e --- /dev/null +++ b/src/vid_ics2595.h @@ -0,0 +1,12 @@ +typedef struct ics2595_t +{ + int oldfs3, oldfs2; + int dat; + int pos; + int state; + + double clocks[16]; + double output_clock; +} ics2595_t; + +void ics2595_write(ics2595_t *ics2595, int strobe, int dat); diff --git a/src/vid_incolor.c b/src/vid_incolor.c new file mode 100644 index 000000000..c4df83bf3 --- /dev/null +++ b/src/vid_incolor.c @@ -0,0 +1,1061 @@ +/*Hercules InColor emulation*/ + +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_incolor.h" + + +/* extended CRTC registers */ + +#define INCOLOR_CRTC_XMODE 20 /* xMode register */ +#define INCOLOR_CRTC_UNDER 21 /* Underline */ +#define INCOLOR_CRTC_OVER 22 /* Overstrike */ +#define INCOLOR_CRTC_EXCEPT 23 /* Exception */ +#define INCOLOR_CRTC_MASK 24 /* Plane display mask & write mask */ +#define INCOLOR_CRTC_RWCTRL 25 /* Read/write control */ +#define INCOLOR_CRTC_RWCOL 26 /* Read/write colour */ +#define INCOLOR_CRTC_PROTECT 27 /* Latch protect */ +#define INCOLOR_CRTC_PALETTE 28 /* Palette */ + +/* character width */ +#define INCOLOR_CW ((incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) ? 8 : 9) + +/* mode control register */ +#define INCOLOR_CTRL_GRAPH 0x02 +#define INCOLOR_CTRL_ENABLE 0x08 +#define INCOLOR_CTRL_BLINK 0x20 +#define INCOLOR_CTRL_PAGE1 0x80 + +/* CRTC status register */ +#define INCOLOR_STATUS_HSYNC 0x01 /* horizontal sync */ +#define INCOLOR_STATUS_LIGHT 0x02 +#define INCOLOR_STATUS_VIDEO 0x08 +#define INCOLOR_STATUS_ID 0x50 /* Card identification */ +#define INCOLOR_STATUS_VSYNC 0x80 /* -vertical sync */ + +/* configuration switch register */ +#define INCOLOR_CTRL2_GRAPH 0x01 +#define INCOLOR_CTRL2_PAGE1 0x02 + +/* extended mode register */ +#define INCOLOR_XMODE_RAMFONT 0x01 +#define INCOLOR_XMODE_90COL 0x02 + + +/* Read/write control */ +#define INCOLOR_RWCTRL_WRMODE 0x30 +#define INCOLOR_RWCTRL_POLARITY 0x40 + +/* exception register */ +#define INCOLOR_EXCEPT_CURSOR 0x0F /* Cursor colour */ +#define INCOLOR_EXCEPT_PALETTE 0x10 /* Enable palette register */ +#define INCOLOR_EXCEPT_ALTATTR 0x20 /* Use alternate attributes */ + + + +/* Default palette */ +static unsigned char defpal[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F +}; + +static uint32_t incolor_rgb[64]; + +/* Mapping of inks to RGB */ +static unsigned char init_rgb[64][3] = +{ + // rgbRGB + { 0x00, 0x00, 0x00 }, // 000000 + { 0x00, 0x00, 0xaa }, // 000001 + { 0x00, 0xaa, 0x00 }, // 000010 + { 0x00, 0xaa, 0xaa }, // 000011 + { 0xaa, 0x00, 0x00 }, // 000100 + { 0xaa, 0x00, 0xaa }, // 000101 + { 0xaa, 0xaa, 0x00 }, // 000110 + { 0xaa, 0xaa, 0xaa }, // 000111 + { 0x00, 0x00, 0x55 }, // 001000 + { 0x00, 0x00, 0xff }, // 001001 + { 0x00, 0xaa, 0x55 }, // 001010 + { 0x00, 0xaa, 0xff }, // 001011 + { 0xaa, 0x00, 0x55 }, // 001100 + { 0xaa, 0x00, 0xff }, // 001101 + { 0xaa, 0xaa, 0x55 }, // 001110 + { 0xaa, 0xaa, 0xff }, // 001111 + { 0x00, 0x55, 0x00 }, // 010000 + { 0x00, 0x55, 0xaa }, // 010001 + { 0x00, 0xff, 0x00 }, // 010010 + { 0x00, 0xff, 0xaa }, // 010011 + { 0xaa, 0x55, 0x00 }, // 010100 + { 0xaa, 0x55, 0xaa }, // 010101 + { 0xaa, 0xff, 0x00 }, // 010110 + { 0xaa, 0xff, 0xaa }, // 010111 + { 0x00, 0x55, 0x55 }, // 011000 + { 0x00, 0x55, 0xff }, // 011001 + { 0x00, 0xff, 0x55 }, // 011010 + { 0x00, 0xff, 0xff }, // 011011 + { 0xaa, 0x55, 0x55 }, // 011100 + { 0xaa, 0x55, 0xff }, // 011101 + { 0xaa, 0xff, 0x55 }, // 011110 + { 0xaa, 0xff, 0xff }, // 011111 + { 0x55, 0x00, 0x00 }, // 100000 + { 0x55, 0x00, 0xaa }, // 100001 + { 0x55, 0xaa, 0x00 }, // 100010 + { 0x55, 0xaa, 0xaa }, // 100011 + { 0xff, 0x00, 0x00 }, // 100100 + { 0xff, 0x00, 0xaa }, // 100101 + { 0xff, 0xaa, 0x00 }, // 100110 + { 0xff, 0xaa, 0xaa }, // 100111 + { 0x55, 0x00, 0x55 }, // 101000 + { 0x55, 0x00, 0xff }, // 101001 + { 0x55, 0xaa, 0x55 }, // 101010 + { 0x55, 0xaa, 0xff }, // 101011 + { 0xff, 0x00, 0x55 }, // 101100 + { 0xff, 0x00, 0xff }, // 101101 + { 0xff, 0xaa, 0x55 }, // 101110 + { 0xff, 0xaa, 0xff }, // 101111 + { 0x55, 0x55, 0x00 }, // 110000 + { 0x55, 0x55, 0xaa }, // 110001 + { 0x55, 0xff, 0x00 }, // 110010 + { 0x55, 0xff, 0xaa }, // 110011 + { 0xff, 0x55, 0x00 }, // 110100 + { 0xff, 0x55, 0xaa }, // 110101 + { 0xff, 0xff, 0x00 }, // 110110 + { 0xff, 0xff, 0xaa }, // 110111 + { 0x55, 0x55, 0x55 }, // 111000 + { 0x55, 0x55, 0xff }, // 111001 + { 0x55, 0xff, 0x55 }, // 111010 + { 0x55, 0xff, 0xff }, // 111011 + { 0xff, 0x55, 0x55 }, // 111100 + { 0xff, 0x55, 0xff }, // 111101 + { 0xff, 0xff, 0x55 }, // 111110 + { 0xff, 0xff, 0xff }, // 111111 +}; + + + +typedef struct incolor_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int dispontime, dispofftime; + int vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int vsynctime, vadj; + + uint8_t palette[16]; /* EGA-style 16 -> 64 palette registers */ + uint8_t palette_idx; /* Palette write index */ + uint8_t latch[4]; /* Memory read/write latches */ + uint8_t *vram; +} incolor_t; + +void incolor_recalctimings(incolor_t *incolor); +void incolor_write(uint32_t addr, uint8_t val, void *p); +uint8_t incolor_read(uint32_t addr, void *p); + + +void incolor_out(uint16_t addr, uint8_t val, void *p) +{ + incolor_t *incolor = (incolor_t *)p; +/* pclog("InColor out %04X %02X\n",addr,val); */ + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + incolor->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (incolor->crtcreg > 28) return; + /* Palette load register */ + if (incolor->crtcreg == INCOLOR_CRTC_PALETTE) + { + incolor->palette[incolor->palette_idx % 16] = val; + ++incolor->palette_idx; + } + incolor->crtc[incolor->crtcreg] = val; + if (incolor->crtc[10] == 6 && incolor->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + incolor->crtc[10] = 0xb; + incolor->crtc[11] = 0xc; + } + incolor_recalctimings(incolor); + return; + case 0x3b8: + incolor->ctrl = val; + return; + case 0x3bf: + incolor->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t incolor_in(uint16_t addr, void *p) +{ + incolor_t *incolor = (incolor_t *)p; +/* pclog("InColor in %04X %02X %04X:%04X %04X\n",addr,(incolor->stat & 0xF) | ((incolor->stat & 8) << 4),CS,pc,CX); */ + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return incolor->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (incolor->crtcreg > 28) return 0xff; + incolor->palette_idx = 0; /* Read resets the palette index */ + return incolor->crtc[incolor->crtcreg]; + case 0x3ba: + /* 0x50: InColor card identity */ + return (incolor->stat & 0xf) | ((incolor->stat & 8) << 4) | 0x50; + } + return 0xff; +} + +void incolor_write(uint32_t addr, uint8_t val, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + egawrites++; + + int plane; + unsigned char wmask = incolor->crtc[INCOLOR_CRTC_MASK]; + unsigned char wmode = incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_WRMODE; + unsigned char fg = incolor->crtc[INCOLOR_CRTC_RWCOL] & 0x0F; + unsigned char bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4)&0x0F; + unsigned char w; + unsigned char vmask; /* Mask of bit within byte */ + unsigned char pmask; /* Mask of plane within colour value */ + unsigned char latch; + + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + + addr &= 0xFFFF; + + /* In text mode, writes to the bottom 16k always touch all 4 planes */ + if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) + { + incolor->vram[addr] = val; + return; + } + + /* There are four write modes: + * 0: 1 => foreground, 0 => background + * 1: 1 => foreground, 0 => source latch + * 2: 1 => source latch, 0 => background + * 3: 1 => source latch, 0 => ~source latch + */ + pmask = 1; + for (plane = 0; plane < 4; pmask <<= 1, wmask >>= 1, addr += 0x10000, + plane++) + { + if (wmask & 0x10) /* Ignore writes to selected plane */ + { + continue; + } + latch = incolor->latch[plane]; + for (vmask = 0x80; vmask != 0; vmask >>= 1) + { + switch (wmode) + { + case 0x00: + if (val & vmask) w = (fg & pmask); + else w = (bg & pmask); + break; + case 0x10: + if (val & vmask) w = (fg & pmask); + else w = (latch & vmask); + break; + case 0x20: + if (val & vmask) w = (latch & vmask); + else w = (bg & pmask); + break; + case 0x30: + if (val & vmask) w = (latch & vmask); + else w = ((~latch) & vmask); + break; + } + /* w is nonzero to write a 1, zero to write a 0 */ + if (w) incolor->vram[addr] |= vmask; + else incolor->vram[addr] &= ~vmask; + } + } +} + +uint8_t incolor_read(uint32_t addr, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + egareads++; + unsigned plane; + unsigned char lp = incolor->crtc[INCOLOR_CRTC_PROTECT]; + unsigned char value = 0; + unsigned char dc; /* "don't care" register */ + unsigned char bg; /* background colour */ + unsigned char fg; + unsigned char mask, pmask; + + addr &= 0xFFFF; + /* Read the four planes into latches */ + for (plane = 0; plane < 4; plane++, addr += 0x10000) + { + incolor->latch[plane] &= lp; + incolor->latch[plane] |= (incolor->vram[addr] & ~lp); + } + addr &= 0xFFFF; + /* In text mode, reads from the bottom 16k assume all planes have + * the same contents */ + if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) + { + return incolor->latch[0]; + } + /* For each pixel, work out if its colour matches the background */ + for (mask = 0x80; mask != 0; mask >>= 1) + { + fg = 0; + dc = incolor->crtc[INCOLOR_CRTC_RWCTRL] & 0x0F; + bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4) & 0x0F; + for (plane = 0, pmask = 1; plane < 4; plane++, pmask <<= 1) + { + if (dc & pmask) + { + fg |= (bg & pmask); + } + else if (incolor->latch[plane] & mask) + { + fg |= pmask; + } + } + if (bg == fg) value |= mask; + } + if (incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY) + { + value = ~value; + } + return value; +} + + + +void incolor_recalctimings(incolor_t *incolor) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = incolor->crtc[0] + 1; + _dispontime = incolor->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + incolor->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + incolor->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void incolor_draw_char_rom(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val; + unsigned ifg, ibg; + const unsigned char *fnt; + uint32_t fg, bg; + int cw = INCOLOR_CW; + + blk = 0; + if (incolor->ctrl & INCOLOR_CTRL_BLINK) + { + if (attr & 0x80) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + { + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + } + else + { + /* CGA-compatible attributes */ + ull = 0xffff; + ifg = attr & 0x0F; + ibg = (attr >> 4) & 0x0F; + } + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + { + fg = incolor_rgb[incolor->palette[ifg]]; + bg = incolor_rgb[incolor->palette[ibg]]; + } + else + { + fg = incolor_rgb[defpal[ifg]]; + bg = incolor_rgb[defpal[ibg]]; + } + + /* ELG set to stretch 8px character to 9px */ + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + + fnt = &(fontdatm[chr][incolor->sc]); + + if (blk) + { + val = 0x000; /* Blinking, draw all background */ + } + else if (incolor->sc == ull) + { + val = 0x1ff; /* Underscore, draw all foreground */ + } + else + { + val = fnt[0] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = (val & 0x100) ? fg : bg; + val = val << 1; + } +} + + +static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val[4]; + unsigned ifg, ibg, cfg, pmask, plane; + const unsigned char *fnt; + uint32_t fg; + int cw = INCOLOR_CW; + int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; + int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + + blk = 0; + if (blink) + { + if (attr & 0x80) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + + if (altattr) + { + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + } + else + { + /* CGA-compatible attributes */ + ull = 0xffff; + ifg = attr & 0x0F; + ibg = (attr >> 4) & 0x0F; + } + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = incolor->vram + 0x4000 + 16 * chr + incolor->sc; + + if (blk) + { + /* Blinking, draw all background */ + val[0] = val[1] = val[2] = val[3] = 0x000; + } + else if (incolor->sc == ull) + { + /* Underscore, draw all foreground */ + val[0] = val[1] = val[2] = val[3] = 0x1ff; + } + else + { + val[0] = fnt[0x00000] << 1; + val[1] = fnt[0x10000] << 1; + val[2] = fnt[0x20000] << 1; + val[3] = fnt[0x30000] << 1; + + if (elg) + { + val[0] |= (val[0] >> 1) & 1; + val[1] |= (val[1] >> 1) & 1; + val[2] |= (val[2] >> 1) & 1; + val[3] |= (val[3] >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + pmask = 1; + for (plane = 0; plane < 4; plane++, pmask = pmask << 1) + { + if (val[plane] & 0x100) cfg |= (ifg & pmask); + else cfg |= (ibg & pmask); + } + /* cfg = colour of foreground pixels */ + if (altattr && (attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ + if (palette) + { + fg = incolor_rgb[incolor->palette[cfg]]; + } + else + { + fg = incolor_rgb[defpal[cfg]]; + } + + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + val[0] = val[0] << 1; + val[1] = val[1] << 1; + val[2] = val[2] << 1; + val[3] = val[3] << 1; + } +} + + +static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk, ul, ol, bld; + unsigned ull, oll, ulc, olc; + unsigned val[4]; + unsigned ifg, ibg, cfg, pmask, plane; + const unsigned char *fnt; + uint32_t fg; + int cw = INCOLOR_CW; + int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; + int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + int font = (attr & 0x0F); + + if (font >= 12) font &= 7; + + blk = 0; + if (blink && altattr) + { + if (attr & 0x40) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + if (altattr) + { + /* MDA-compatible attributes */ + if (blink) + { + ibg = (attr & 0x80) ? 8 : 0; + bld = 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + else + { + bld = (attr & 0x80) ? 1 : 0; + ibg = (attr & 0x40) ? 0x0F : 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + } + else + { + /* CGA-compatible attributes */ + ibg = 0; + ifg = (attr >> 4) & 0x0F; + ol = 0; + ul = 0; + bld = 0; + } + if (ul) + { + ull = incolor->crtc[INCOLOR_CRTC_UNDER] & 0x0F; + ulc = (incolor->crtc[INCOLOR_CRTC_UNDER] >> 4) & 0x0F; + if (ulc == 0) ulc = 7; + } + else + { + ull = 0xFFFF; + } + if (ol) + { + oll = incolor->crtc[INCOLOR_CRTC_OVER] & 0x0F; + olc = (incolor->crtc[INCOLOR_CRTC_OVER] >> 4) & 0x0F; + if (olc == 0) olc = 7; + } + else + { + oll = 0xFFFF; + } + + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = incolor->vram + 0x4000 + 16 * chr + 4096 * font + incolor->sc; + + if (blk) + { + /* Blinking, draw all background */ + val[0] = val[1] = val[2] = val[3] = 0x000; + } + else if (incolor->sc == ull) + { + /* Underscore, draw all foreground */ + val[0] = val[1] = val[2] = val[3] = 0x1ff; + } + else + { + val[0] = fnt[0x00000] << 1; + val[1] = fnt[0x10000] << 1; + val[2] = fnt[0x20000] << 1; + val[3] = fnt[0x30000] << 1; + + if (elg) + { + val[0] |= (val[0] >> 1) & 1; + val[1] |= (val[1] >> 1) & 1; + val[2] |= (val[2] >> 1) & 1; + val[3] |= (val[3] >> 1) & 1; + } + if (bld) + { + val[0] |= (val[0] >> 1); + val[1] |= (val[1] >> 1); + val[2] |= (val[2] >> 1); + val[3] |= (val[3] >> 1); + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + pmask = 1; + if (incolor->sc == oll) + { + cfg = olc ^ ibg; /* Strikethrough */ + } + else if (incolor->sc == ull) + { + cfg = ulc ^ ibg; /* Underline */ + } + else + { + for (plane = 0; plane < 4; plane++, pmask = pmask << 1) + { + if (val[plane] & 0x100) + { + if (altattr) cfg |= ((~ibg) & pmask); + else cfg |= ((~ifg) & pmask); + } + else if (altattr) cfg |= (ibg & pmask); + } + } + if (palette) + { + fg = incolor_rgb[incolor->palette[cfg]]; + } + else + { + fg = incolor_rgb[defpal[cfg]]; + } + + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + val[0] = val[0] << 1; + val[1] = val[1] << 1; + val[2] = val[2] << 1; + val[3] = val[3] << 1; + } +} + + + + + + +static void incolor_text_line(incolor_t *incolor, uint16_t ca) +{ + int drawcursor; + int x, c; + uint8_t chr, attr; + uint32_t col; + + for (x = 0; x < incolor->crtc[1]; x++) + { + chr = incolor->vram[(incolor->ma << 1) & 0x3fff]; + attr = incolor->vram[((incolor->ma << 1) + 1) & 0x3fff]; + + drawcursor = ((incolor->ma == ca) && incolor->con && incolor->cursoron); + + switch (incolor->crtc[INCOLOR_CRTC_XMODE] & 5) + { + case 0: + case 4: /* ROM font */ + incolor_draw_char_rom(incolor, x, chr, attr); + break; + case 1: /* 4k RAMfont */ + incolor_draw_char_ram4(incolor, x, chr, attr); + break; + case 5: /* 48k RAMfont */ + incolor_draw_char_ram48(incolor, x, chr, attr); + break; + + } + ++incolor->ma; + if (drawcursor) + { + int cw = INCOLOR_CW; + uint8_t ink = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_CURSOR; + if (ink == 0) ink = (attr & 0x08) | 7; + + /* In MDA-compatible mode, cursor brightness comes from + * background */ + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + { + ink = (attr & 0x08) | (ink & 7); + } + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + { + col = incolor_rgb[incolor->palette[ink]]; + } + else + { + col = incolor_rgb[defpal[ink]]; + } + for (c = 0; c < cw; c++) + { + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + c] = col; + } + } + } +} + + +static void incolor_graphics_line(incolor_t *incolor) +{ + uint8_t mask; + uint16_t ca; + int x, c, plane, col; + uint8_t ink; + uint16_t val[4]; + + /* Graphics mode. */ + ca = (incolor->sc & 3) * 0x2000; + if ((incolor->ctrl & INCOLOR_CTRL_PAGE1) && (incolor->ctrl2 & INCOLOR_CTRL2_PAGE1)) + ca += 0x8000; + + for (x = 0; x < incolor->crtc[1]; x++) + { + mask = incolor->crtc[INCOLOR_CRTC_MASK]; /* Planes to display */ + for (plane = 0; plane < 4; plane++, mask = mask >> 1) + { + if (mask & 1) + val[plane] = (incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | + incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + else val[plane] = 0; + } + incolor->ma++; + for (c = 0; c < 16; c++) + { + ink = 0; + for (plane = 0; plane < 4; plane++) + { + ink = ink >> 1; + if (val[plane] & 0x8000) ink |= 8; + val[plane] = val[plane] << 1; + } + /* Is palette in use? */ + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + col = incolor->palette[ink]; + else col = defpal[ink]; + + ((uint32_t *)buffer32->line[incolor->displine])[(x << 4) + c] = incolor_rgb[col]; + } + } +} + +void incolor_poll(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + uint16_t ca = (incolor->crtc[15] | (incolor->crtc[14] << 8)) & 0x3fff; + int x; + int oldvc; + int oldsc; + + if (!incolor->linepos) + { +// pclog("InColor poll %i %i\n", incolor->vc, incolor->sc); + incolor->vidtime += incolor->dispofftime; + incolor->stat |= 1; + incolor->linepos = 1; + oldsc = incolor->sc; + if ((incolor->crtc[8] & 3) == 3) + incolor->sc = (incolor->sc << 1) & 7; + if (incolor->dispon) + { + if (incolor->displine < incolor->firstline) + { + incolor->firstline = incolor->displine; + } + incolor->lastline = incolor->displine; + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + incolor_graphics_line(incolor); + } + else + { + incolor_text_line(incolor, ca); + } + } + incolor->sc = oldsc; + if (incolor->vc == incolor->crtc[7] && !incolor->sc) + { + incolor->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + incolor->displine++; + if (incolor->displine >= 500) + incolor->displine = 0; + } + else + { + incolor->vidtime += incolor->dispontime; + if (incolor->dispon) + incolor->stat &= ~1; + incolor->linepos = 0; + if (incolor->vsynctime) + { + incolor->vsynctime--; + if (!incolor->vsynctime) + { + incolor->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (incolor->sc == (incolor->crtc[11] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[11] & 31) >> 1))) + { + incolor->con = 0; + incolor->coff = 1; + } + if (incolor->vadj) + { + incolor->sc++; + incolor->sc &= 31; + incolor->ma = incolor->maback; + incolor->vadj--; + if (!incolor->vadj) + { + incolor->dispon = 1; + incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; + incolor->sc = 0; + } + } + else if (incolor->sc == incolor->crtc[9] || ((incolor->crtc[8] & 3) == 3 && incolor->sc == (incolor->crtc[9] >> 1))) + { + incolor->maback = incolor->ma; + incolor->sc = 0; + oldvc = incolor->vc; + incolor->vc++; + incolor->vc &= 127; + if (incolor->vc == incolor->crtc[6]) + incolor->dispon = 0; + if (oldvc == incolor->crtc[4]) + { +// printf("Display over at %i\n",displine); + incolor->vc = 0; + incolor->vadj = incolor->crtc[5]; + if (!incolor->vadj) incolor->dispon=1; + if (!incolor->vadj) incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; + if ((incolor->crtc[10] & 0x60) == 0x20) incolor->cursoron = 0; + else incolor->cursoron = incolor->blink & 16; + } + if (incolor->vc == incolor->crtc[7]) + { + incolor->dispon = 0; + incolor->displine = 0; + incolor->vsynctime = 16;//(crtcm[3]>>4)+1; + if (incolor->crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + x = incolor->crtc[1] << 4; + } + else + { + x = incolor->crtc[1] * 9; + } + incolor->lastline++; + if (x != xsize || (incolor->lastline - incolor->firstline) != ysize) + { + xsize = x; + ysize = incolor->lastline - incolor->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + startblit(); + video_blit_memtoscreen(0, incolor->firstline, 0, incolor->lastline - incolor->firstline, xsize, incolor->lastline - incolor->firstline); + endblit(); + frames++; + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + video_res_x = incolor->crtc[1] * 16; + video_res_y = incolor->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = incolor->crtc[1]; + video_res_y = incolor->crtc[6]; + video_bpp = 0; + } + } + incolor->firstline = 1000; + incolor->lastline = 0; + incolor->blink++; + } + } + else + { + incolor->sc++; + incolor->sc &= 31; + incolor->ma = incolor->maback; + } + if ((incolor->sc == (incolor->crtc[10] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[10] & 31) >> 1)))) + { + incolor->con = 1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + +void *incolor_init() +{ + int c; + incolor_t *incolor = malloc(sizeof(incolor_t)); + memset(incolor, 0, sizeof(incolor_t)); + + incolor->vram = malloc(0x40000); /* 4 planes of 64k */ + + timer_add(incolor_poll, &incolor->vidtime, TIMER_ALWAYS_ENABLED, incolor); + mem_mapping_add(&incolor->mapping, 0xb0000, 0x08000, incolor_read, NULL, NULL, incolor_write, NULL, NULL, NULL, 0, incolor); + io_sethandler(0x03b0, 0x0010, incolor_in, NULL, NULL, incolor_out, NULL, NULL, incolor); + + for (c = 0; c < 64; c++) + { + incolor_rgb[c] = makecol32(init_rgb[c][0], init_rgb[c][1], init_rgb[c][2]); + } + +/* Initialise CRTC regs to safe values */ + incolor->crtc[INCOLOR_CRTC_MASK ] = 0x0F; /* All planes displayed */ + incolor->crtc[INCOLOR_CRTC_RWCTRL] = INCOLOR_RWCTRL_POLARITY; + incolor->crtc[INCOLOR_CRTC_RWCOL ] = 0x0F; /* White on black */ + incolor->crtc[INCOLOR_CRTC_EXCEPT] = INCOLOR_EXCEPT_ALTATTR; + for (c = 0; c < 16; c++) + { + incolor->palette[c] = defpal[c]; + } + incolor->palette_idx = 0; + + + + return incolor; +} + +void incolor_close(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + free(incolor->vram); + free(incolor); +} + +void incolor_speed_changed(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + incolor_recalctimings(incolor); +} + +device_t incolor_device = +{ + "Hercules InColor", + 0, + incolor_init, + incolor_close, + NULL, + incolor_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_incolor.h b/src/vid_incolor.h new file mode 100644 index 000000000..297b7b42e --- /dev/null +++ b/src/vid_incolor.h @@ -0,0 +1 @@ +extern device_t incolor_device; diff --git a/src/vid_mda.c b/src/vid_mda.c new file mode 100644 index 000000000..8d30b9ff3 --- /dev/null +++ b/src/vid_mda.c @@ -0,0 +1,328 @@ +/*MDA emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_mda.h" + +typedef struct mda_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, stat; + + int dispontime, dispofftime; + int vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int vsynctime, vadj; + + uint8_t *vram; +} mda_t; + +static int mdacols[256][2][2]; + +void mda_recalctimings(mda_t *mda); + +void mda_out(uint16_t addr, uint8_t val, void *p) +{ + mda_t *mda = (mda_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + mda->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + mda->crtc[mda->crtcreg] = val; + if (mda->crtc[10] == 6 && mda->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + mda->crtc[10] = 0xb; + mda->crtc[11] = 0xc; + } + mda_recalctimings(mda); + return; + case 0x3b8: + mda->ctrl = val; + return; + } +} + +uint8_t mda_in(uint16_t addr, void *p) +{ + mda_t *mda = (mda_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return mda->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + return mda->crtc[mda->crtcreg]; + case 0x3ba: + return mda->stat | 0xF0; + } + return 0xff; +} + +void mda_write(uint32_t addr, uint8_t val, void *p) +{ + mda_t *mda = (mda_t *)p; + egawrites++; + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + mda->vram[addr & 0xfff] = val; +} + +uint8_t mda_read(uint32_t addr, void *p) +{ + mda_t *mda = (mda_t *)p; + egareads++; + return mda->vram[addr & 0xfff]; +} + +void mda_recalctimings(mda_t *mda) +{ + double _dispontime, _dispofftime, disptime; + disptime = mda->crtc[0] + 1; + _dispontime = mda->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + mda->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + mda->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void mda_poll(void *p) +{ + mda_t *mda = (mda_t *)p; + uint16_t ca = (mda->crtc[15] | (mda->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + int cols[4]; + int oldsc; + int blink; + if (!mda->linepos) + { + mda->vidtime += mda->dispofftime; + mda->stat |= 1; + mda->linepos = 1; + oldsc = mda->sc; + if ((mda->crtc[8] & 3) == 3) + mda->sc = (mda->sc << 1) & 7; + if (mda->dispon) + { + if (mda->displine < mda->firstline) + { + mda->firstline = mda->displine; + } + mda->lastline = mda->displine; + cols[0] = 0; + cols[1] = 7; + for (x = 0; x < mda->crtc[1]; x++) + { + chr = mda->vram[(mda->ma << 1) & 0x3fff]; + attr = mda->vram[((mda->ma << 1) + 1) & 0x3fff]; + drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); + blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + if (mda->sc == 12 && ((attr & 7) == 1)) + { + for (c = 0; c < 9; c++) + buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][1]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][mda->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][mda->sc] & 1]; + else buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + } + mda->ma++; + if (drawcursor) + { + for (c = 0; c < 9; c++) + buffer->line[mda->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + } + } + } + mda->sc = oldsc; + if (mda->vc == mda->crtc[7] && !mda->sc) + { + mda->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + mda->displine++; + if (mda->displine >= 500) + mda->displine=0; + } + else + { + mda->vidtime += mda->dispontime; + if (mda->dispon) mda->stat&=~1; + mda->linepos=0; + if (mda->vsynctime) + { + mda->vsynctime--; + if (!mda->vsynctime) + { + mda->stat&=~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) + { + mda->con = 0; + mda->coff = 1; + } + if (mda->vadj) + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + mda->vadj--; + if (!mda->vadj) + { + mda->dispon = 1; + mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + mda->sc = 0; + } + } + else if (mda->sc == mda->crtc[9] || ((mda->crtc[8] & 3) == 3 && mda->sc == (mda->crtc[9] >> 1))) + { + mda->maback = mda->ma; + mda->sc = 0; + oldvc = mda->vc; + mda->vc++; + mda->vc &= 127; + if (mda->vc == mda->crtc[6]) + mda->dispon=0; + if (oldvc == mda->crtc[4]) + { +// printf("Display over at %i\n",displine); + mda->vc = 0; + mda->vadj = mda->crtc[5]; + if (!mda->vadj) mda->dispon = 1; + if (!mda->vadj) mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + if ((mda->crtc[10] & 0x60) == 0x20) mda->cursoron = 0; + else mda->cursoron = mda->blink & 16; + } + if (mda->vc == mda->crtc[7]) + { + mda->dispon = 0; + mda->displine = 0; + mda->vsynctime = 16; + if (mda->crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + x = mda->crtc[1] * 9; + mda->lastline++; + if (x != xsize || (mda->lastline - mda->firstline) != ysize) + { + xsize = x; + ysize = mda->lastline - mda->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + startblit(); + video_blit_memtoscreen_8(0, mda->firstline, xsize, mda->lastline - mda->firstline); + endblit(); + frames++; + video_res_x = mda->crtc[1]; + video_res_y = mda->crtc[6]; + video_bpp = 0; + } + mda->firstline = 1000; + mda->lastline = 0; + mda->blink++; + } + } + else + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + } + if ((mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1)))) + { + mda->con = 1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + +void *mda_init() +{ + int c; + mda_t *mda = malloc(sizeof(mda_t)); + memset(mda, 0, sizeof(mda_t)); + + mda->vram = malloc(0x1000); + + timer_add(mda_poll, &mda->vidtime, TIMER_ALWAYS_ENABLED, mda); + mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, 0, mda); + io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + overscan_x = overscan_y = 0; + + return mda; +} + +void mda_close(void *p) +{ + mda_t *mda = (mda_t *)p; + + free(mda->vram); + free(mda); +} + +void mda_speed_changed(void *p) +{ + mda_t *mda = (mda_t *)p; + + mda_recalctimings(mda); +} + +device_t mda_device = +{ + "MDA", + 0, + mda_init, + mda_close, + NULL, + mda_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_mda.h b/src/vid_mda.h new file mode 100644 index 000000000..682c671e2 --- /dev/null +++ b/src/vid_mda.h @@ -0,0 +1 @@ +extern device_t mda_device; diff --git a/src/vid_olivetti_m24.c b/src/vid_olivetti_m24.c new file mode 100644 index 000000000..5889022a3 --- /dev/null +++ b/src/vid_olivetti_m24.c @@ -0,0 +1,490 @@ +/*Olivetti M24 video emulation + Essentially double-res CGA*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_olivetti_m24.h" + +typedef struct m24_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t *vram; + uint8_t charbuffer[256]; + + uint8_t ctrl; + uint32_t base; + + uint8_t cgamode, cgacol; + uint8_t stat; + + int linepos, displine; + int sc, vc; + int con, coff, cursoron, blink; + int vsynctime, vadj; + int lineff; + uint16_t ma, maback; + int dispon; + + int dispontime, dispofftime, vidtime; + + int firstline, lastline; +} m24_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void m24_recalctimings(m24_t *m24); + + +void m24_out(uint16_t addr, uint8_t val, void *p) +{ + m24_t *m24 = (m24_t *)p; + uint8_t old; +// pclog("m24_out %04X %02X\n", addr, val); + switch (addr) + { + case 0x3d4: + m24->crtcreg = val & 31; + return; + case 0x3d5: + old = m24->crtc[m24->crtcreg]; + m24->crtc[m24->crtcreg] = val & crtcmask[m24->crtcreg]; + if (old != val) + { + if (m24->crtcreg < 0xe || m24->crtcreg > 0x10) + { + fullchange = changeframecount; + m24_recalctimings(m24); + } + } + return; + case 0x3d8: + m24->cgamode = val; + return; + case 0x3d9: + m24->cgacol = val; + return; + case 0x3de: + m24->ctrl = val; + m24->base = (val & 0x08) ? 0x4000 : 0; + return; + } +} + +uint8_t m24_in(uint16_t addr, void *p) +{ + m24_t *m24 = (m24_t *)p; + switch (addr) + { + case 0x3d4: + return m24->crtcreg; + case 0x3d5: + return m24->crtc[m24->crtcreg]; + case 0x3da: + return m24->stat; + } + return 0xff; +} + +void m24_write(uint32_t addr, uint8_t val, void *p) +{ + m24_t *m24 = (m24_t *)p; + m24->vram[addr & 0x7FFF]=val; + m24->charbuffer[ ((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc] = val; + m24->charbuffer[(((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc) | 1] = val; +} + +uint8_t m24_read(uint32_t addr, void *p) +{ + m24_t *m24 = (m24_t *)p; + return m24->vram[addr & 0x7FFF]; +} + +void m24_recalctimings(m24_t *m24) +{ + double _dispontime, _dispofftime, disptime; + if (m24->cgamode & 1) + { + disptime = m24->crtc[0] + 1; + _dispontime = m24->crtc[1]; + } + else + { + disptime = (m24->crtc[0] + 1) << 1; + _dispontime = m24->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; +// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); + _dispontime *= CGACONST / 2; + _dispofftime *= CGACONST / 2; +// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); + m24->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + m24->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void m24_poll(void *p) +{ + m24_t *m24 = (m24_t *)p; + uint16_t ca = (m24->crtc[15] | (m24->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat, dat2; + int cols[4]; + int col; + int oldsc; + if (!m24->linepos) + { +// pclog("Line poll %i %i %i %i - %04X %i %i %i\n", m24_lineff, vc, sc, vadj, ma, firstline, lastline, displine); + m24->vidtime += m24->dispofftime; + m24->stat |= 1; + m24->linepos = 1; + oldsc = m24->sc; + if ((m24->crtc[8] & 3) == 3) + m24->sc = (m24->sc << 1) & 7; + if (m24->dispon) + { + pclog("dispon %i\n", m24->linepos); + if (m24->displine < m24->firstline) + { + m24->firstline = m24->displine; +// printf("Firstline %i\n",firstline); + } + m24->lastline = m24->displine; + for (c = 0; c < 8; c++) + { + if ((m24->cgamode & 0x12) == 0x12) + { + buffer->line[m24->displine][c] = 0; + if (m24->cgamode & 1) buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = 0; + else buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[m24->displine][c] = (m24->cgacol & 15) + 16; + if (m24->cgamode & 1) buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = (m24->cgacol & 15) + 16; + else buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = (m24->cgacol & 15) + 16; + } + } + if (m24->cgamode & 1) + { + for (x = 0; x < m24->crtc[1]; x++) + { + chr = m24->charbuffer[ x << 1]; + attr = m24->charbuffer[(x << 1) + 1]; + drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); + if (m24->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((m24->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + m24->ma++; + } + } + else if (!(m24->cgamode & 2)) + { + for (x = 0; x < m24->crtc[1]; x++) + { + chr = m24->vram[((m24->ma << 1) & 0x3fff) + m24->base]; + attr = m24->vram[(((m24->ma << 1) + 1) & 0x3fff) + m24->base]; + drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); + if (m24->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((m24->blink & 16) && (attr & 0x80)) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + m24->ma++; + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = + buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = + buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + else if (!(m24->cgamode & 16)) + { + cols[0] = (m24->cgacol & 15) | 16; + col = (m24->cgacol & 16) ? 24 : 16; + if (m24->cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (m24->cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < m24->crtc[1]; x++) + { + dat = (m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + m24->base] << 8) | + m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + 1 + m24->base]; + m24->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = + buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + if (m24->ctrl & 1) + { + dat2 = ((m24->sc & 1) * 0x4000) | (m24->lineff * 0x2000); + cols[0] = 0; cols[1] = /*(m24->cgacol & 15)*/15 + 16; + } + else + { + dat2 = (m24->sc & 1) * 0x2000; + cols[0] = 0; cols[1] = (m24->cgacol & 15) + 16; + } + for (x = 0; x < m24->crtc[1]; x++) + { + dat = (m24->vram[((m24->ma << 1) & 0x1fff) + dat2] << 8) | m24->vram[((m24->ma << 1) & 0x1fff) + dat2 + 1]; + m24->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[m24->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + cols[0] = ((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15) + 16; + if (m24->cgamode & 1) hline(buffer, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]); + } + + if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16; + else x = (m24->crtc[1] << 4) + 16; + + m24->sc = oldsc; + if (m24->vc == m24->crtc[7] && !m24->sc) + m24->stat |= 8; + m24->displine++; + if (m24->displine >= 720) m24->displine = 0; + } + else + { +// pclog("Line poll %i %i %i %i\n", m24_lineff, vc, sc, vadj); + m24->vidtime += m24->dispontime; + if (m24->dispon) m24->stat &= ~1; + m24->linepos = 0; + m24->lineff ^= 1; + if (m24->lineff) + { + m24->ma = m24->maback; + } + else + { + if (m24->vsynctime) + { + m24->vsynctime--; + if (!m24->vsynctime) + m24->stat &= ~8; + } + if (m24->sc == (m24->crtc[11] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[11] & 31) >> 1))) + { + m24->con = 0; + m24->coff = 1; + } + if (m24->vadj) + { + m24->sc++; + m24->sc &= 31; + m24->ma = m24->maback; + m24->vadj--; + if (!m24->vadj) + { + m24->dispon = 1; + m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff; + m24->sc = 0; + } + } + else if (m24->sc == m24->crtc[9] || ((m24->crtc[8] & 3) == 3 && m24->sc == (m24->crtc[9] >> 1))) + { + m24->maback = m24->ma; + m24->sc = 0; + oldvc = m24->vc; + m24->vc++; + m24->vc &= 127; + + if (m24->vc == m24->crtc[6]) + m24->dispon=0; + + if (oldvc == m24->crtc[4]) + { + m24->vc = 0; + m24->vadj = m24->crtc[5]; + if (!m24->vadj) m24->dispon = 1; + if (!m24->vadj) m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff; + if ((m24->crtc[10] & 0x60) == 0x20) m24->cursoron = 0; + else m24->cursoron = m24->blink & 16; + } + + if (m24->vc == m24->crtc[7]) + { + m24->dispon = 0; + m24->displine = 0; + m24->vsynctime = (m24->crtc[3] >> 4) + 1; + if (m24->crtc[7]) + { + if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16; + else x = (m24->crtc[1] << 4) + 16; + m24->lastline++; + if (x != xsize || (m24->lastline - m24->firstline) != ysize) + { + xsize = x; + ysize = m24->lastline - m24->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize + 16); + } +startblit(); + video_blit_memtoscreen_8(0, m24->firstline - 8, xsize, (m24->lastline - m24->firstline) + 16); + frames++; +endblit(); + video_res_x = xsize - 16; + video_res_y = ysize; + if (m24->cgamode & 1) + { + video_res_x /= 8; + video_res_y /= (m24->crtc[9] + 1) * 2; + video_bpp = 0; + } + else if (!(m24->cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= (m24->crtc[9] + 1) * 2; + video_bpp = 0; + } + else if (!(m24->cgamode & 16)) + { + video_res_x /= 2; + video_res_y /= 2; + video_bpp = 2; + } + else if (!(m24->ctrl & 1)) + { + video_res_y /= 2; + video_bpp = 1; + } + } + m24->firstline = 1000; + m24->lastline = 0; + m24->blink++; + } + } + else + { + m24->sc++; + m24->sc &= 31; + m24->ma = m24->maback; + } + if ((m24->sc == (m24->crtc[10] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[10] & 31) >> 1)))) + m24->con = 1; + } + if (m24->dispon && (m24->cgamode & 1)) + { + for (x = 0; x < (m24->crtc[1] << 1); x++) + m24->charbuffer[x] = m24->vram[(((m24->ma << 1) + x) & 0x3fff) + m24->base]; + } + } +} + +void *m24_init() +{ + int c; + m24_t *m24 = malloc(sizeof(m24_t)); + memset(m24, 0, sizeof(m24_t)); + + m24->vram = malloc(0x8000); + + timer_add(m24_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24); + mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, m24_read, NULL, NULL, m24_write, NULL, NULL, NULL, 0, m24); + io_sethandler(0x03d0, 0x0010, m24_in, NULL, NULL, m24_out, NULL, NULL, m24); + overscan_x = overscan_y = 16; + return m24; +} + +void m24_close(void *p) +{ + m24_t *m24 = (m24_t *)p; + + free(m24->vram); + free(m24); +} + +void m24_speed_changed(void *p) +{ + m24_t *m24 = (m24_t *)p; + + m24_recalctimings(m24); +} + +device_t m24_device = +{ + "Olivetti M24 (video)", + 0, + m24_init, + m24_close, + NULL, + m24_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_olivetti_m24.h b/src/vid_olivetti_m24.h new file mode 100644 index 000000000..8558cc7c6 --- /dev/null +++ b/src/vid_olivetti_m24.h @@ -0,0 +1 @@ +extern device_t m24_device; diff --git a/src/vid_oti067.c b/src/vid_oti067.c new file mode 100644 index 000000000..1c9cc5f33 --- /dev/null +++ b/src/vid_oti067.c @@ -0,0 +1,343 @@ +/*Oak OTI067 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_oti067.h" +#include "vid_svga.h" + +typedef struct oti067_t +{ + svga_t svga; + + rom_t bios_rom; + + int index; + uint8_t regs[32]; + + uint8_t pos; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t chip_id; +} oti067_t; + +void oti067_out(uint16_t addr, uint8_t val, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + svga_t *svga = &oti067->svga; + uint8_t old; + +// pclog("oti067_out : %04X %02X %02X %i\n", addr, val, ram[0x489], ins); + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 31; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x3DE: + oti067->index = val & 0x1f; + return; + case 0x3DF: + oti067->regs[oti067->index] = val; + switch (oti067->index) + { + case 0xD: + svga->vrammask = (val & 0xc) ? oti067->vram_mask : 0x3ffff; + if ((val & 0x80) && oti067->vram_size == 256) + mem_mapping_disable(&svga->mapping); + else + mem_mapping_enable(&svga->mapping); + if (!(val & 0x80)) + svga->vrammask = 0x3ffff; + break; + case 0x11: + svga->read_bank = (val & 0xf) * 65536; + svga->write_bank = (val >> 4) * 65536; + break; + } + return; + } + svga_out(addr, val, svga); +} + +uint8_t oti067_in(uint16_t addr, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + svga_t *svga = &oti067->svga; + uint8_t temp; + +// if (addr != 0x3da && addr != 0x3ba) pclog("oti067_in : %04X ", addr); + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + + case 0x3DE: + temp = oti067->index | (oti067->chip_id << 5); + // temp = oti067->index | (2 << 5); + break; + case 0x3DF: + if (oti067->index==0x10) temp = 0x18; + else temp = oti067->regs[oti067->index]; + break; + + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da && addr != 0x3ba) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +void oti067_pos_out(uint16_t addr, uint8_t val, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + if ((val & 8) != (oti067->pos & 8)) + { + if (val & 8) + io_sethandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067); + else + io_removehandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067); + } + + oti067->pos = val; +} + +uint8_t oti067_pos_in(uint16_t addr, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + return oti067->pos; +} + +void oti067_recalctimings(svga_t *svga) +{ + oti067_t *oti067 = (oti067_t *)svga->p; + + if (oti067->regs[0x14] & 0x08) svga->ma_latch |= 0x10000; + if (oti067->regs[0x0d] & 0x0c) svga->rowoffset <<= 1; + // svga->interlace = oti067->regs[0x14] & 0x80; + if (oti067->regs[0x14] & 0x80) + { + svga->vtotal *= 2; + svga->dispend *= 2; + svga->vblankstart *= 2; + svga->vsyncstart *=2; + svga->split *= 2; + } +} + +void *oti067_common_init(char *bios_fn, int vram_size, int chip_id) +{ + oti067_t *oti067 = malloc(sizeof(oti067_t)); + memset(oti067, 0, sizeof(oti067_t)); + + rom_init(&oti067->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + oti067->vram_size = vram_size; + oti067->vram_mask = (vram_size << 10) - 1; + + oti067->chip_id = chip_id; + + svga_init(&oti067->svga, oti067, vram_size << 10, + oti067_recalctimings, + oti067_in, oti067_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067); + io_sethandler(0x46e8, 0x0001, oti067_pos_in, NULL, NULL, oti067_pos_out, NULL, NULL, oti067); + + oti067->svga.miscout = 1; + return oti067; +} + +void *oti067_init() +{ + int vram_size = device_get_config_int("memory"); + return oti067_common_init("roms/oti067/bios.bin", vram_size, 2); +} + +void *oti077_init() +{ + int vram_size = device_get_config_int("memory"); + return oti067_common_init("roms/oti077.vbi", vram_size, 5); +} + +void *oti067_acer386_init() +{ + oti067_t *oti067 = oti067_common_init("roms/acer386/oti067.bin", 512, 2); + + if (oti067) + oti067->bios_rom.rom[0x5d] = 0x74; + + return oti067; +} + +static int oti067_available() +{ + return rom_present("roms/oti067/bios.bin"); +} + +static int oti077_available() +{ + return rom_present("roms/oti077.vbi"); +} + +void oti067_close(void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + svga_close(&oti067->svga); + + free(oti067); +} + +void oti067_speed_changed(void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + svga_recalctimings(&oti067->svga); +} + +void oti067_force_redraw(void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + oti067->svga.fullchange = changeframecount; +} + +void oti067_add_status_info(char *s, int max_len, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + svga_add_status_info(s, max_len, &oti067->svga); +} + +static device_config_t oti067_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "" + } + }, + .default_int = 512 + }, + { + .type = -1 + } +}; + +static device_config_t oti077_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + }, + .default_int = 1024 + }, + { + .type = -1 + } +}; + +device_t oti067_device = +{ + "Oak OTI-067", + 0, + oti067_init, + oti067_close, + oti067_available, + oti067_speed_changed, + oti067_force_redraw, + oti067_add_status_info, + oti067_config +}; +device_t oti067_acer386_device = +{ + "Oak OTI-067 (Acermate 386SX/25N)", + 0, + oti067_acer386_init, + oti067_close, + oti067_available, + oti067_speed_changed, + oti067_force_redraw, + oti067_add_status_info +}; +device_t oti077_device = +{ + "Oak OTI-077", + 0, + oti077_init, + oti067_close, + oti077_available, + oti067_speed_changed, + oti067_force_redraw, + oti067_add_status_info, + oti077_config +}; diff --git a/src/vid_oti067.h b/src/vid_oti067.h new file mode 100644 index 000000000..2c76fe80c --- /dev/null +++ b/src/vid_oti067.h @@ -0,0 +1,3 @@ +extern device_t oti067_device; +extern device_t oti067_acer386_device; +extern device_t oti077_device; diff --git a/src/vid_paradise.c b/src/vid_paradise.c new file mode 100644 index 000000000..2ea3f399a --- /dev/null +++ b/src/vid_paradise.c @@ -0,0 +1,463 @@ +/*Paradise VGA emulation + + PC2086, PC3086 use PVGA1A + MegaPC uses W90C11A + */ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_paradise.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_unk_ramdac.h" + +typedef struct paradise_t +{ + svga_t svga; + + rom_t bios_rom; + + enum + { + PVGA1A = 0, + WD90C11 + } type; + + uint32_t read_bank[4], write_bank[4]; +} paradise_t; + +void paradise_write(uint32_t addr, uint8_t val, void *p); +uint8_t paradise_read(uint32_t addr, void *p); +void paradise_remap(paradise_t *paradise); + + +void paradise_out(uint16_t addr, uint8_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + svga_t *svga = ¶dise->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; +// output = 3; +// pclog("Paradise out %04X %02X %04X:%04X\n", addr, val, CS, pc); + switch (addr) + { + case 0x3c5: + if (svga->seqaddr > 7) + { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return; + svga->seqregs[svga->seqaddr & 0x1f] = val; + if (svga->seqaddr == 0x11) + paradise_remap(paradise); + return; + } + break; + + case 0x3cf: + if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) + { + if ((svga->gdcreg[0xf] & 7) != 5) + return; + } + if (svga->gdcaddr == 6) + { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) + { +// pclog("Write mapping %02X\n", val); + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + svga->gdcreg[6] = val; + paradise_remap(paradise); + return; + } + if (svga->gdcaddr == 0x9 || svga->gdcaddr == 0xa) + { + svga->gdcreg[svga->gdcaddr] = val; + paradise_remap(paradise); + return; + } + if (svga->gdcaddr == 0xe) + { + svga->gdcreg[0xe] = val; + paradise_remap(paradise); + return; + } + break; + + case 0x3D4: + if (paradise->type == PVGA1A) + svga->crtcreg = val & 0x1f; + else + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg > 0x29 && (svga->crtc[0x29] & 7) != 5) + return; + if (svga->crtcreg >= 0x31 && svga->crtcreg <= 0x37) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(¶dise->svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t paradise_in(uint16_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + svga_t *svga = ¶dise->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("Paradise in %04X\n", addr); + switch (addr) + { + case 0x3c2: + return 0x10; + + case 0x3c5: + if (svga->seqaddr > 7) + { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return 0xff; + if (svga->seqaddr > 0x12) + return 0xff; + return svga->seqregs[svga->seqaddr & 0x1f]; + } + break; + + case 0x3cf: + if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) + { + if (svga->gdcreg[0xf] & 0x10) + return 0xff; + switch (svga->gdcaddr) + { + case 0xf: + return (svga->gdcreg[0xf] & 0x17) | 0x80; + } + } + break; + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x29 && svga->crtcreg < 0x30 && (svga->crtc[0x29] & 0x88) != 0x80) + return 0xff; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void paradise_remap(paradise_t *paradise) +{ + svga_t *svga = ¶dise->svga; + + if (svga->seqregs[0x11] & 0x80) + { +// pclog("Remap 1\n"); + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12; + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0xa] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else if (svga->gdcreg[0xe] & 0x08) + { + if (svga->gdcreg[0x6] & 0xc) + { +// pclog("Remap 2\n"); + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12; + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else + { +// pclog("Remap 3\n"); + paradise->read_bank[0] = paradise->write_bank[0] = (svga->gdcreg[0xa] & 0x7f) << 12; + paradise->read_bank[1] = paradise->write_bank[1] = ((svga->gdcreg[0xa] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->read_bank[2] = paradise->write_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; + paradise->read_bank[3] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + } + else + { + // pclog("Remap 4\n"); + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } +// pclog("Remap - %04X %04X\n", paradise->read_bank[0], paradise->write_bank[0]); +} + +void paradise_recalctimings(svga_t *svga) +{ + svga->lowres = !(svga->gdcreg[0xe] & 0x01); + if (svga->bpp == 8 && !svga->lowres) + svga->render = svga_render_8bpp_highres; +} + +#define egacycles 1 +#define egacycles2 1 +void paradise_write(uint32_t addr, uint8_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; +// pclog("paradise_write : %05X %02X ", addr, val); + addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; +// pclog("%08X\n", addr); + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + svga_write_linear(addr, val, ¶dise->svga); +} + +uint8_t paradise_read(uint32_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; +// pclog("paradise_read : %05X ", addr); + addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; +// pclog("%08X\n", addr); + return svga_read_linear(addr, ¶dise->svga); +} + +void *paradise_pvga1a_init() +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, 1 << 18, /*256kb*/ + NULL, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = PVGA1A; + + return paradise; +} + +void *paradise_wd90c11_init() +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, 1 << 19, /*512kb*/ + paradise_recalctimings, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + svga->crtc[0x36] = '1'; + svga->crtc[0x37] = '1'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = WD90C11; + + return paradise; +} + +static void *paradise_pvga1a_pc2086_init() +{ + paradise_t *paradise = paradise_pvga1a_init(); + + if (paradise) + rom_init(¶dise->bios_rom, "roms/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} +static void *paradise_pvga1a_pc3086_init() +{ + paradise_t *paradise = paradise_pvga1a_init(); + + if (paradise) + rom_init(¶dise->bios_rom, "roms/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static void *paradise_wd90c11_megapc_init() +{ + paradise_t *paradise = paradise_wd90c11_init(); + + if (paradise) + rom_init_interleaved(¶dise->bios_rom, + "roms/megapc/41651-bios lo.u18", + "roms/megapc/211253-bios hi.u19", + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int paradise_wd90c11_standalone_available() +{ + return rom_present("roms/megapc/41651-bios lo.u18") && rom_present("roms/megapc/211253-bios hi.u19"); +} + +static void *cpqvga_init() +{ + paradise_t *paradise = paradise_pvga1a_init(); + + if (paradise) + rom_init(¶dise->bios_rom, "roms/1988-05-18.rom", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int cpqvga_standalone_available() +{ + return rom_present("roms/1988-05-18.rom"); +} + +void paradise_close(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_close(¶dise->svga); + + free(paradise); +} + +void paradise_speed_changed(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_recalctimings(¶dise->svga); +} + +void paradise_force_redraw(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + paradise->svga.fullchange = changeframecount; +} + +void paradise_add_status_info(char *s, int max_len, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_add_status_info(s, max_len, ¶dise->svga); +} + +device_t paradise_pvga1a_pc2086_device = +{ + "Paradise PVGA1A (Amstrad PC2086)", + 0, + paradise_pvga1a_pc2086_init, + paradise_close, + NULL, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; +device_t paradise_pvga1a_pc3086_device = +{ + "Paradise PVGA1A (Amstrad PC3086)", + 0, + paradise_pvga1a_pc3086_init, + paradise_close, + NULL, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; +device_t paradise_wd90c11_megapc_device = +{ + "Paradise WD90C11 (Amstrad MegaPC)", + 0, + paradise_wd90c11_megapc_init, + paradise_close, + NULL, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; +device_t paradise_wd90c11_device = +{ + "Paradise WD90C11", + 0, + paradise_wd90c11_megapc_init, + paradise_close, + paradise_wd90c11_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; +device_t cpqvga_device = +{ + "Compaq/Paradise VGA", + 0, + cpqvga_init, + paradise_close, + cpqvga_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; diff --git a/src/vid_paradise.h b/src/vid_paradise.h new file mode 100644 index 000000000..44d74dd4a --- /dev/null +++ b/src/vid_paradise.h @@ -0,0 +1,5 @@ +extern device_t paradise_pvga1a_pc2086_device; +extern device_t paradise_pvga1a_pc3086_device; +extern device_t paradise_wd90c11_megapc_device; +extern device_t paradise_wd90c11_device; +extern device_t cpqvga_device; diff --git a/src/vid_pc1512.c b/src/vid_pc1512.c new file mode 100644 index 000000000..8beef9074 --- /dev/null +++ b/src/vid_pc1512.c @@ -0,0 +1,494 @@ +/*PC1512 CGA emulation + + The PC1512 extends CGA with a bit-planar 640x200x16 mode. + + Most CRTC registers are fixed. + + The Technical Reference Manual lists the video waitstate time as between 12 + and 46 cycles. PCem currently always uses the lower number.*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_pc1512.h" + +typedef struct pc1512_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t cgacol, cgamode, stat; + + uint8_t plane_write, plane_read, border; + + int linepos, displine; + int sc, vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + uint16_t ma, maback; + int dispon; + int blink; + + int dispontime, dispofftime, vidtime; + int firstline, lastline; + + uint8_t *vram; +} pc1512_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void pc1512_recalctimings(pc1512_t *pc1512); + +static void pc1512_out(uint16_t addr, uint8_t val, void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + uint8_t old; +// pclog("PC1512 out %04X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x3d4: + pc1512->crtcreg = val & 31; + return; + case 0x3d5: + old = pc1512->crtc[pc1512->crtcreg]; + pc1512->crtc[pc1512->crtcreg] = val & crtcmask[pc1512->crtcreg]; + if (old != val) + { + if (pc1512->crtcreg < 0xe || pc1512->crtcreg > 0x10) + { + fullchange = changeframecount; + pc1512_recalctimings(pc1512); + } + } + return; + case 0x3d8: + if ((val & 0x12) == 0x12 && (pc1512->cgamode & 0x12) != 0x12) + { + pc1512->plane_write = 0xf; + pc1512->plane_read = 0; + } + pc1512->cgamode = val; + return; + case 0x3d9: + pc1512->cgacol = val; + return; + case 0x3dd: + pc1512->plane_write = val; + return; + case 0x3de: + pc1512->plane_read = val & 3; + return; + case 0x3df: + pc1512->border = val; + return; + } +} + +static uint8_t pc1512_in(uint16_t addr, void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; +// pclog("PC1512 in %04X %02X %04X:%04X\n",addr,CS,pc); + switch (addr) + { + case 0x3d4: + return pc1512->crtcreg; + case 0x3d5: + return pc1512->crtc[pc1512->crtcreg]; + case 0x3da: + return pc1512->stat; + } + return 0xff; +} + +static void pc1512_write(uint32_t addr, uint8_t val, void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + + egawrites++; + cycles -= 12; + addr &= 0x3fff; + + if ((pc1512->cgamode & 0x12) == 0x12) + { + if (pc1512->plane_write & 1) pc1512->vram[addr] = val; + if (pc1512->plane_write & 2) pc1512->vram[addr | 0x4000] = val; + if (pc1512->plane_write & 4) pc1512->vram[addr | 0x8000] = val; + if (pc1512->plane_write & 8) pc1512->vram[addr | 0xc000] = val; + } + else + pc1512->vram[addr] = val; +} + +static uint8_t pc1512_read(uint32_t addr, void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + + egareads++; + cycles -= 12; + addr &= 0x3fff; + + if ((pc1512->cgamode & 0x12) == 0x12) + return pc1512->vram[addr | (pc1512->plane_read << 14)]; + return pc1512->vram[addr]; +} + + +static void pc1512_recalctimings(pc1512_t *pc1512) +{ + double _dispontime, _dispofftime, disptime; + disptime = 128; /*Fixed on PC1512*/ + _dispontime = 80; + _dispofftime = disptime - _dispontime; +// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); + _dispontime *= CGACONST; + _dispofftime *= CGACONST; +// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); + pc1512->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + pc1512->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +static void pc1512_poll(void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + uint16_t ca = (pc1512->crtc[15] | (pc1512->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat, dat2, dat3, dat4; + int cols[4]; + int col; + int oldsc; + + if (!pc1512->linepos) + { + pc1512->vidtime += pc1512->dispofftime; + pc1512->stat |= 1; + pc1512->linepos = 1; + oldsc = pc1512->sc; + if (pc1512->dispon) + { + if (pc1512->displine < pc1512->firstline) + pc1512->firstline = pc1512->displine; + pc1512->lastline = pc1512->displine; + for (c = 0; c < 8; c++) + { + if ((pc1512->cgamode & 0x12) == 0x12) + { + buffer->line[pc1512->displine][c] = (pc1512->border & 15) + 16; + if (pc1512->cgamode & 1) buffer->line[pc1512->displine][c + (pc1512->crtc[1] << 3) + 8] = 0; + else buffer->line[pc1512->displine][c + (pc1512->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[pc1512->displine][c] = (pc1512->cgacol & 15) + 16; + if (pc1512->cgamode & 1) buffer->line[pc1512->displine][c + (pc1512->crtc[1] << 3) + 8] = (pc1512->cgacol & 15) + 16; + else buffer->line[pc1512->displine][c + (pc1512->crtc[1] << 4) + 8] = (pc1512->cgacol & 15) + 16; + } + } + if (pc1512->cgamode & 1) + { + for (x = 0; x < 80; x++) + { + chr = pc1512->vram[ ((pc1512->ma << 1) & 0x3fff)]; + attr = pc1512->vram[(((pc1512->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((pc1512->ma == ca) && pc1512->con && pc1512->cursoron); + if (pc1512->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((pc1512->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[pc1512->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pc1512->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + pc1512->ma++; + } + } + else if (!(pc1512->cgamode & 2)) + { + for (x = 0; x < 40; x++) + { + chr = pc1512->vram[ ((pc1512->ma << 1) & 0x3fff)]; + attr = pc1512->vram[(((pc1512->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((pc1512->ma == ca) && pc1512->con && pc1512->cursoron); + if (pc1512->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((pc1512->blink & 16) && (attr & 0x80)) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + pc1512->ma++; + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + else if (!(pc1512->cgamode&16)) + { + cols[0] = (pc1512->cgacol & 15) | 16; + col = (pc1512->cgacol & 16) ? 24 : 16; + if (pc1512->cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (pc1512->cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < 40; x++) + { + dat = (pc1512->vram[((pc1512->ma << 1) & 0x1fff) + ((pc1512->sc & 1) * 0x2000)] << 8) | pc1512->vram[((pc1512->ma << 1) & 0x1fff) + ((pc1512->sc & 1) * 0x2000) + 1]; + pc1512->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + for (x = 0; x < 40; x++) + { + ca = ((pc1512->ma << 1) & 0x1fff) + ((pc1512->sc & 1) * 0x2000); + dat = (pc1512->vram[ca] << 8) | pc1512->vram[ca + 1]; + dat2 = (pc1512->vram[ca + 0x4000] << 8) | pc1512->vram[ca + 0x4001]; + dat3 = (pc1512->vram[ca + 0x8000] << 8) | pc1512->vram[ca + 0x8001]; + dat4 = (pc1512->vram[ca + 0xc000] << 8) | pc1512->vram[ca + 0xc001]; + + pc1512->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[pc1512->displine][(x << 4) + c + 8] = (((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (pc1512->cgacol & 15)) + 16; + dat <<= 1; + dat2 <<= 1; + dat3 <<= 1; + dat4 <<= 1; + } + } + } + } + else + { + cols[0] = ((pc1512->cgamode & 0x12) == 0x12) ? 0 : (pc1512->cgacol & 15) + 16; + if (pc1512->cgamode & 1) hline(buffer, 0, pc1512->displine, (pc1512->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, pc1512->displine, (pc1512->crtc[1] << 4) + 16, cols[0]); + } + + pc1512->sc = oldsc; + if (pc1512->vsynctime) + pc1512->stat |= 8; + pc1512->displine++; + if (pc1512->displine >= 360) + pc1512->displine = 0; +// pclog("Line %i %i %i %i %i %i\n",displine,cgadispon,firstline,lastline,vc,sc); + } + else + { + pc1512->vidtime += pc1512->dispontime; + if ((pc1512->lastline - pc1512->firstline) == 199) + pc1512->dispon = 0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ + if (pc1512->dispon) + pc1512->stat &= ~1; + pc1512->linepos = 0; + if (pc1512->vsynctime) + { + pc1512->vsynctime--; + if (!pc1512->vsynctime) + pc1512->stat &= ~8; + } + if (pc1512->sc == (pc1512->crtc[11] & 31)) + { + pc1512->con = 0; + pc1512->coff = 1; + } + if (pc1512->vadj) + { + pc1512->sc++; + pc1512->sc &= 31; + pc1512->ma = pc1512->maback; + pc1512->vadj--; + if (!pc1512->vadj) + { + pc1512->dispon = 1; + pc1512->ma = pc1512->maback = (pc1512->crtc[13] | (pc1512->crtc[12] << 8)) & 0x3fff; + pc1512->sc = 0; + } + } + else if (pc1512->sc == pc1512->crtc[9]) + { + pc1512->maback = pc1512->ma; + pc1512->sc = 0; + oldvc = pc1512->vc; + pc1512->vc++; + pc1512->vc &= 127; + + if (pc1512->displine == 32)//oldvc == (cgamode & 2) ? 127 : 31) + { + pc1512->vc = 0; + pc1512->vadj = 6; + if ((pc1512->crtc[10] & 0x60) == 0x20) pc1512->cursoron = 0; + else pc1512->cursoron = pc1512->blink & 16; + } + + if (pc1512->displine >= 262)//vc == (cgamode & 2) ? 111 : 27) + { + pc1512->dispon = 0; + pc1512->displine = 0; + pc1512->vsynctime = 46; + + if (pc1512->cgamode&1) x = (pc1512->crtc[1] << 3) + 16; + else x = (pc1512->crtc[1] << 4) + 16; + x = 640 + 16; + pc1512->lastline++; + + if (x != xsize || (pc1512->lastline - pc1512->firstline) != ysize) + { + xsize = x; + ysize = pc1512->lastline - pc1512->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } +startblit(); + video_blit_memtoscreen_8(0, pc1512->firstline - 4, xsize, (pc1512->lastline - pc1512->firstline) + 8); +// blit(buffer,vbuf,0,firstline-4,0,0,xsize,(lastline-firstline)+8+1); +// if (vid_resize) stretch_blit(vbuf,screen,0,0,xsize,(lastline-firstline)+8+1,0,0,winsizex,winsizey); +// else stretch_blit(vbuf,screen,0,0,xsize,(lastline-firstline)+8+1,0,0,xsize,((lastline-firstline)<<1)+16+2); +// if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF); +// readflash=0; +endblit(); + video_res_x = xsize - 16; + video_res_y = ysize; + if (pc1512->cgamode & 1) + { + video_res_x /= 8; + video_res_y /= pc1512->crtc[9] + 1; + video_bpp = 0; + } + else if (!(pc1512->cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= pc1512->crtc[9] + 1; + video_bpp = 0; + } + else if (!(pc1512->cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 4; + } + + pc1512->firstline = 1000; + pc1512->lastline = 0; + pc1512->blink++; + } + } + else + { + pc1512->sc++; + pc1512->sc &= 31; + pc1512->ma = pc1512->maback; + } + if (pc1512->sc == (pc1512->crtc[10] & 31)) + pc1512->con = 1; + } +} + +static void *pc1512_init() +{ + int c; + pc1512_t *pc1512 = malloc(sizeof(pc1512_t)); + memset(pc1512, 0, sizeof(pc1512_t)); + + pc1512->vram = malloc(0x10000); + + pc1512->cgacol = 7; + pc1512->cgamode = 0x12; + + timer_add(pc1512_poll, &pc1512->vidtime, TIMER_ALWAYS_ENABLED, pc1512); + mem_mapping_add(&pc1512->mapping, 0xb8000, 0x08000, pc1512_read, NULL, NULL, pc1512_write, NULL, NULL, NULL, 0, pc1512); + io_sethandler(0x03d0, 0x0010, pc1512_in, NULL, NULL, pc1512_out, NULL, NULL, pc1512); + overscan_x = overscan_y = 16; + return pc1512; +} + +static void pc1512_close(void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + + free(pc1512->vram); + free(pc1512); +} + +static void pc1512_speed_changed(void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + + pc1512_recalctimings(pc1512); +} + +device_t pc1512_device = +{ + "Amstrad PC1512 (video)", + 0, + pc1512_init, + pc1512_close, + NULL, + pc1512_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_pc1512.h b/src/vid_pc1512.h new file mode 100644 index 000000000..fec42d6cd --- /dev/null +++ b/src/vid_pc1512.h @@ -0,0 +1 @@ +extern device_t pc1512_device; diff --git a/src/vid_pc1640.c b/src/vid_pc1640.c new file mode 100644 index 000000000..963e74813 --- /dev/null +++ b/src/vid_pc1640.c @@ -0,0 +1,164 @@ +/*PC1640 video emulation. + Mostly standard EGA, but with CGA & Hercules emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "timer.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_ega.h" +#include "vid_pc1640.h" + +typedef struct pc1640_t +{ + mem_mapping_t cga_mapping; + mem_mapping_t ega_mapping; + + cga_t cga; + ega_t ega; + + rom_t bios_rom; + + int cga_enabled; + int dispontime, dispofftime, vidtime; +} pc1640_t; + +void pc1640_out(uint16_t addr, uint8_t val, void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + + switch (addr) + { + case 0x3db: + pc1640->cga_enabled = val & 0x40; + if (pc1640->cga_enabled) + { + mem_mapping_enable(&pc1640->cga_mapping); + mem_mapping_disable(&pc1640->ega_mapping); + } + else + { + mem_mapping_disable(&pc1640->cga_mapping); + switch (pc1640->ega.gdcreg[6] & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&pc1640->ega_mapping, 0xa0000, 0x20000); + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&pc1640->ega_mapping, 0xa0000, 0x10000); + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&pc1640->ega_mapping, 0xb0000, 0x08000); + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&pc1640->ega_mapping, 0xb8000, 0x08000); + break; + } + } + pclog("3DB write %02X\n", val); + return; + } + if (pc1640->cga_enabled) cga_out(addr, val, &pc1640->cga); + else ega_out(addr, val, &pc1640->ega); +} + +uint8_t pc1640_in(uint16_t addr, void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + + switch (addr) + { + } + + if (pc1640->cga_enabled) return cga_in(addr, &pc1640->cga); + else return ega_in(addr, &pc1640->ega); +} + +void pc1640_recalctimings(pc1640_t *pc1640) +{ + cga_recalctimings(&pc1640->cga); + ega_recalctimings(&pc1640->ega); + if (pc1640->cga_enabled) + { + overscan_x = overscan_y = 16; + pc1640->dispontime = pc1640->cga.dispontime; + pc1640->dispofftime = pc1640->cga.dispofftime; + } + else + { + overscan_x = 16; overscan_y = 28; + pc1640->dispontime = pc1640->ega.dispontime; + pc1640->dispofftime = pc1640->ega.dispofftime; + } +} + +void pc1640_poll(void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + if (pc1640->cga_enabled) + { + overscan_x = overscan_y = 16; + pc1640->cga.vidtime = pc1640->vidtime; + cga_poll(&pc1640->cga); + pc1640->vidtime = pc1640->cga.vidtime; + } + else + { + overscan_x = 16; overscan_y = 28; + pc1640->ega.vidtime = pc1640->vidtime; + ega_poll(&pc1640->ega); + pc1640->vidtime = pc1640->ega.vidtime; + } +} + +void *pc1640_init() +{ + pc1640_t *pc1640 = malloc(sizeof(pc1640_t)); + cga_t *cga = &pc1640->cga; + ega_t *ega = &pc1640->ega; + memset(pc1640, 0, sizeof(pc1640_t)); + + rom_init(&pc1640->bios_rom, "roms/pc1640/40100", 0xc0000, 0x8000, 0x7fff, 0, 0); + + ega_init(&pc1640->ega); + pc1640->cga.vram = pc1640->ega.vram; + pc1640->cga_enabled = 1; + cga_init(&pc1640->cga); + + timer_add(pc1640_poll, &pc1640->vidtime, TIMER_ALWAYS_ENABLED, pc1640); + mem_mapping_add(&pc1640->cga_mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + mem_mapping_add(&pc1640->ega_mapping, 0, 0, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); + io_sethandler(0x03a0, 0x0040, pc1640_in, NULL, NULL, pc1640_out, NULL, NULL, pc1640); + overscan_x = overscan_y = 16; + return pc1640; +} + +void pc1640_close(void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + + free(pc1640->ega.vram); + free(pc1640); +} + +void pc1640_speed_changed(void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + + pc1640_recalctimings(pc1640); +} + +device_t pc1640_device = +{ + "Amstrad PC1640 (video)", + 0, + pc1640_init, + pc1640_close, + NULL, + pc1640_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_pc1640.h b/src/vid_pc1640.h new file mode 100644 index 000000000..c836fd400 --- /dev/null +++ b/src/vid_pc1640.h @@ -0,0 +1 @@ +extern device_t pc1640_device; diff --git a/src/vid_pc200.c b/src/vid_pc200.c new file mode 100644 index 000000000..414ccae28 --- /dev/null +++ b/src/vid_pc200.c @@ -0,0 +1,146 @@ +/*PC200 video emulation. + CGA with some NMI stuff. But we don't need that as it's only used for TV and + LCD displays, and we're emulating a CRT*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_pc200.h" + +typedef struct pc200_t +{ + mem_mapping_t mapping; + + cga_t cga; + + uint8_t reg_3dd, reg_3de, reg_3df; +} pc200_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void pc200_out(uint16_t addr, uint8_t val, void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + cga_t *cga = &pc200->cga; + uint8_t old; + + switch (addr) + { + case 0x3d5: + if (!(pc200->reg_3de & 0x40) && cga->crtcreg <= 11) + { + if (pc200->reg_3de & 0x80) + nmi = 1; + + pc200->reg_3dd = 0x20 | (cga->crtcreg & 0x1f); + pc200->reg_3df = val; + return; + } + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; + if (old != val) + { + if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) + { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + + case 0x3d8: + old = cga->cgamode; + cga->cgamode = val; + if ((cga->cgamode ^ old) & 3) + cga_recalctimings(cga); + pc200->reg_3dd |= 0x80; + if (pc200->reg_3de & 0x80) + nmi = 1; + return; + + case 0x3de: + pc200->reg_3de = val; + pc200->reg_3dd = 0x1f; + if (val & 0x80) + pc200->reg_3dd |= 0x40; + return; + } + cga_out(addr, val, cga); +} + +uint8_t pc200_in(uint16_t addr, void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + cga_t *cga = &pc200->cga; + uint8_t temp; + + switch (addr) + { + case 0x3D8: + return cga->cgamode; + + case 0x3DD: + temp = pc200->reg_3dd; + pc200->reg_3dd &= 0x1f; + nmi = 0; + return temp; + + case 0x3DE: + return (pc200->reg_3de & 0xc7) | 0x10; /*External CGA*/ + + case 0x3DF: + return pc200->reg_3df; + } + return cga_in(addr, cga); +} + +void *pc200_init() +{ + pc200_t *pc200 = malloc(sizeof(pc200_t)); + cga_t *cga = &pc200->cga; + memset(pc200, 0, sizeof(pc200_t)); + + pc200->cga.vram = malloc(0x4000); + cga_init(&pc200->cga); + + timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + mem_mapping_add(&pc200->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + io_sethandler(0x03d0, 0x0010, pc200_in, NULL, NULL, pc200_out, NULL, NULL, pc200); + overscan_x = overscan_y = 16; + return pc200; +} + +void pc200_close(void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + + free(pc200->cga.vram); + free(pc200); +} + +void pc200_speed_changed(void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + + cga_recalctimings(&pc200->cga); +} + +device_t pc200_device = +{ + "Amstrad PC200 (video)", + 0, + pc200_init, + pc200_close, + NULL, + pc200_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_pc200.h b/src/vid_pc200.h new file mode 100644 index 000000000..cbb2cb58c --- /dev/null +++ b/src/vid_pc200.h @@ -0,0 +1 @@ +extern device_t pc200_device; diff --git a/src/vid_pcjr.c b/src/vid_pcjr.c new file mode 100644 index 000000000..a35da6d80 --- /dev/null +++ b/src/vid_pcjr.c @@ -0,0 +1,647 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_pcjr.h" + +static int i_filt[8],q_filt[8]; + +typedef struct pcjr_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[32]; + int array_ff; + int memctrl;//=-1; + uint8_t stat; + int addr_mode; + + uint8_t *vram, *b8000; + + int linepos, displine; + int sc, vc; + int dispon; + int con, coff, cursoron, blink; + int vsynctime, vadj; + uint16_t ma, maback; + + int dispontime, dispofftime, vidtime; + int firstline, lastline; +} pcjr_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void pcjr_recalcaddress(pcjr_t *pcjr); +void pcjr_recalctimings(pcjr_t *pcjr); + +void pcjr_out(uint16_t addr, uint8_t val, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + uint8_t old; +// pclog("pcjr OUT %04X %02X\n",addr,val); + switch (addr) + { + case 0x3d4: + pcjr->crtcreg = val & 0x1f; + return; + case 0x3d5: +// pclog("CRTC write %02X %02x\n", pcjr->crtcreg, val); + old = pcjr->crtc[pcjr->crtcreg]; + pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; + if (old != val) + { + if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) + { + fullchange = changeframecount; + pcjr_recalctimings(pcjr); + } + } + return; + case 0x3da: +// pclog("Array write %02X %02X\n", pcjr->array_index, val); + if (!pcjr->array_ff) + pcjr->array_index = val & 0x1f; + else + { + if (pcjr->array_index & 0x10) + val &= 0x0f; + pcjr->array[pcjr->array_index & 0x1f] = val; + } + pcjr->array_ff = !pcjr->array_ff; + break; + case 0x3df: + pcjr->memctrl = val; + pcjr->addr_mode = val >> 6; + pcjr_recalcaddress(pcjr); + break; + } +} + +uint8_t pcjr_in(uint16_t addr, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; +// if (addr!=0x3DA) pclog("pcjr IN %04X\n",addr); + switch (addr) + { + case 0x3d4: + return pcjr->crtcreg; + case 0x3d5: + return pcjr->crtc[pcjr->crtcreg]; + case 0x3da: + pcjr->array_ff = 0; + pcjr->stat ^= 0x10; + return pcjr->stat; + } + return 0xFF; +} + +void pcjr_recalcaddress(pcjr_t *pcjr) +{ + if ((pcjr->memctrl & 0xc0) == 0xc0) + { + pcjr->vram = &ram[(pcjr->memctrl & 0x06) << 14]; + pcjr->b8000 = &ram[(pcjr->memctrl & 0x30) << 11]; +// printf("VRAM at %05X B8000 at %05X\n",((pcjr->memctrl&0x6)<<14)+pcjr->base,((pcjr->memctrl&0x30)<<11)+pcjr->base); + } + else + { + pcjr->vram = &ram[(pcjr->memctrl & 0x07) << 14]; + pcjr->b8000 = &ram[(pcjr->memctrl & 0x38) << 11]; +// printf("VRAM at %05X B8000 at %05X\n",((pcjr->memctrl&0x7)<<14)+pcjr->base,((pcjr->memctrl&0x38)<<11)+pcjr->base); + } +} + +void pcjr_write(uint32_t addr, uint8_t val, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + if (pcjr->memctrl == -1) + return; + + egawrites++; +// pclog("pcjr VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI); + pcjr->b8000[addr & 0x3fff] = val; +} + +uint8_t pcjr_read(uint32_t addr, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + if (pcjr->memctrl == -1) + return 0xff; + + egareads++; +// pclog("pcjr VRAM read %05X %02X %04X:%04X\n",addr,pcjr->b8000[addr&0x7FFF],CS,pc); + return pcjr->b8000[addr & 0x3fff]; +} + +void pcjr_recalctimings(pcjr_t *pcjr) +{ + double _dispontime, _dispofftime, disptime; + if (pcjr->array[0] & 1) + { + disptime = pcjr->crtc[0] + 1; + _dispontime = pcjr->crtc[1]; + } + else + { + disptime = (pcjr->crtc[0] + 1) << 1; + _dispontime = pcjr->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + pcjr->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + pcjr->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +/*static int cga4pal[8][4]= +{ + {0,2,4,6},{0,3,5,7},{0,3,4,7},{0,3,4,7}, + {0,10,12,14},{0,11,13,15},{0,11,12,15},{0,11,12,15} +};*/ + +void pcjr_poll(void *p) +{ +// int *cgapal=cga4pal[((pcjr->col&0x10)>>2)|((cgamode&4)>>1)|((cgacol&0x20)>>5)]; + pcjr_t *pcjr = (pcjr_t *)p; + uint16_t ca = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + int y_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, y_val, y_tot; + int i_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, i_val, i_tot; + int q_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, q_val, q_tot; + int r, g, b; + if (!pcjr->linepos) + { +// cgapal[0]=pcjr->col&15; +// printf("Firstline %i Lastline %i pcjr->displine %i\n",firstline,lastline,pcjr->displine); + pcjr->vidtime += pcjr->dispofftime; + pcjr->stat &= ~1; + pcjr->linepos = 1; + oldsc = pcjr->sc; + if ((pcjr->crtc[8] & 3) == 3) + pcjr->sc = (pcjr->sc << 1) & 7; + if (pcjr->dispon) + { + uint16_t offset = 0; + uint16_t mask = 0x1fff; + + if (pcjr->displine < pcjr->firstline) + pcjr->firstline = pcjr->displine; + pcjr->lastline = pcjr->displine; + cols[0] = (pcjr->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) + { + buffer->line[pcjr->displine][c] = cols[0]; + if (pcjr->array[0] & 1) buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 3) + 8] = cols[0]; + else buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 4) + 8] = cols[0]; + } + + switch (pcjr->addr_mode) + { + case 0: /*Alpha*/ + offset = 0; + mask = 0x3fff; + break; + case 1: /*Low resolution graphics*/ + offset = (pcjr->sc & 1) * 0x2000; + break; + case 3: /*High resolution graphics*/ + offset = (pcjr->sc & 3) * 0x2000; + break; + } + switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) + { + case 0x13: /*320x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer->line[pcjr->displine][(x << 3) + 8] = + buffer->line[pcjr->displine][(x << 3) + 9] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 10] = + buffer->line[pcjr->displine][(x << 3) + 11] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 12] = + buffer->line[pcjr->displine][(x << 3) + 13] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 14] = + buffer->line[pcjr->displine][(x << 3) + 15] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + } + break; + case 0x12: /*160x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer->line[pcjr->displine][(x << 4) + 8] = + buffer->line[pcjr->displine][(x << 4) + 9] = + buffer->line[pcjr->displine][(x << 4) + 10] = + buffer->line[pcjr->displine][(x << 4) + 11] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 12] = + buffer->line[pcjr->displine][(x << 4) + 13] = + buffer->line[pcjr->displine][(x << 4) + 14] = + buffer->line[pcjr->displine][(x << 4) + 15] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 16] = + buffer->line[pcjr->displine][(x << 4) + 17] = + buffer->line[pcjr->displine][(x << 4) + 18] = + buffer->line[pcjr->displine][(x << 4) + 19] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 20] = + buffer->line[pcjr->displine][(x << 4) + 21] = + buffer->line[pcjr->displine][(x << 4) + 22] = + buffer->line[pcjr->displine][(x << 4) + 23] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + } + break; + case 0x03: /*640x200x4*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 8; c++) + { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[pcjr->displine][(x << 3) + 8 + c] = pcjr->array[(chr & pcjr->array[1]) + 16] + 16; + dat <<= 1; + } + } + break; + case 0x01: /*80 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); + if (pcjr->array[3] & 4) + { + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16] + 16; + } + if (pcjr->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } +// if (!((ma^(crtc[15]|(crtc[14]<<8)))&0x3FFF)) printf("Cursor match! %04X\n",ma); + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] ^= 15; + } + pcjr->ma++; + } + break; + case 0x00: /*40 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); + if (pcjr->array[3] & 4) + { + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16] + 16; + } + pcjr->ma++; + if (pcjr->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) + { + for (c = 0; c < 16; c++) + buffer->line[pcjr->displine][(x << 4) + c + 8] ^= 15; + } + } + break; + case 0x02: /*320x200x4*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + cols[2] = pcjr->array[2 + 16] + 16; + cols[3] = pcjr->array[3 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + break; + case 0x102: /*640x200x2*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[pcjr->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + break; + } + } + else + { + if (pcjr->array[3] & 4) + { + if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, (pcjr->array[2] & 0xf) + 16); + else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, (pcjr->array[2] & 0xf) + 16); + } + else + { +// cols[0] = ((pcjr->mode & 0x12) == 0x12) ? 0 : (pcjr->col & 0xf) + 16; + cols[0] = pcjr->array[0 + 16] + 16; + if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, cols[0]); + } + } + if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; + else x = (pcjr->crtc[1] << 4) + 16; + if (cga_comp) + { + for (c = 0; c < x; c++) + { + y_buf[(c << 1) & 6] = ntsc_col[buffer->line[pcjr->displine][c] & 7][(c << 1) & 6] ? 0x6000 : 0; + y_buf[(c << 1) & 6] += (buffer->line[pcjr->displine][c] & 8) ? 0x3000 : 0; + i_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * i_filt[(c << 1) & 6]; + q_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * q_filt[(c << 1) & 6]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + + y_buf[((c << 1) & 6) + 1] = ntsc_col[buffer->line[pcjr->displine][c] & 7][((c << 1) & 6) + 1] ? 0x6000 : 0; + y_buf[((c << 1) & 6) + 1] += (buffer->line[pcjr->displine][c] & 8) ? 0x3000 : 0; + i_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * i_filt[((c << 1) & 6) + 1]; + q_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * q_filt[((c << 1) & 6) + 1]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + if (r > 511) r = 511; + if (g > 511) g = 511; + if (b > 511) b = 511; + + ((uint32_t *)buffer32->line[pcjr->displine])[c] = makecol32(r / 2, g / 2, b / 2); + } + } + pcjr->sc = oldsc; + if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) + { + pcjr->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + pcjr->displine++; + if (pcjr->displine >= 360) + pcjr->displine = 0; + } + else + { + pcjr->vidtime += pcjr->dispontime; + if (pcjr->dispon) + pcjr->stat |= 1; + pcjr->linepos = 0; + if (pcjr->vsynctime) + { + pcjr->vsynctime--; + if (!pcjr->vsynctime) + { + pcjr->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) + { + pcjr->con = 0; + pcjr->coff = 1; + } + if (pcjr->vadj) + { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + pcjr->vadj--; + if (!pcjr->vadj) + { + pcjr->dispon = 1; + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + pcjr->sc = 0; +// printf("Display on!\n"); + } + } + else if (pcjr->sc == pcjr->crtc[9] || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == (pcjr->crtc[9] >> 1))) + { + pcjr->maback = pcjr->ma; +// con=0; +// coff=0; + pcjr->sc = 0; + oldvc = pcjr->vc; + pcjr->vc++; + pcjr->vc &= 127; +// pclog("VC %i %i\n", pcjr->vc, pcjr->crtc[7]); +// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],pcjr->dispon); + if (pcjr->vc == pcjr->crtc[6]) + pcjr->dispon = 0; + if (oldvc == pcjr->crtc[4]) + { +// printf("Display over at %i\n",pcjr->displine); + pcjr->vc = 0; + pcjr->vadj = pcjr->crtc[5]; + if (!pcjr->vadj) + pcjr->dispon = 1; + if (!pcjr->vadj) + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + if ((pcjr->crtc[10] & 0x60) == 0x20) pcjr->cursoron = 0; + else pcjr->cursoron = pcjr->blink & 16; +// printf("CRTC10 %02X %i\n",crtc[10],cursoron); + } + if (pcjr->vc == pcjr->crtc[7]) + { + pcjr->dispon = 0; + pcjr->displine = 0; + pcjr->vsynctime = 16;//(crtc[3]>>4)+1; + picint(1 << 5); +// printf("pcjr->vsynctime %i %02X\n",pcjr->vsynctime,crtc[3]); +// pcjr->stat|=8; + if (pcjr->crtc[7]) + { +// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize); + if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; + else x = (pcjr->crtc[1] << 4) + 16; + pcjr->lastline++; + if (x != xsize || (pcjr->lastline - pcjr->firstline) != ysize) + { + xsize = x; + ysize = pcjr->lastline - pcjr->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtc[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } +// printf("Blit %i %i\n",firstline,lastline); +//printf("Xsize is %i\n",xsize); + startblit(); + if (cga_comp) + video_blit_memtoscreen(0, pcjr->firstline-4, 0, (pcjr->lastline - pcjr->firstline) + 8, xsize, (pcjr->lastline - pcjr->firstline) + 8); + else + video_blit_memtoscreen_8(0, pcjr->firstline-4, xsize, (pcjr->lastline - pcjr->firstline) + 8); + endblit(); + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + } + pcjr->firstline = 1000; + pcjr->lastline = 0; + pcjr->blink++; + } + } + else + { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + } + if ((pcjr->sc == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[10] & 31) >> 1)))) + pcjr->con = 1; + } +} + +static void *pcjr_video_init() +{ + int c; + int pcjr_tint = -2; + pcjr_t *pcjr = malloc(sizeof(pcjr_t)); + memset(pcjr, 0, sizeof(pcjr_t)); + + pcjr->memctrl = -1; + + for (c = 0; c < 8; c++) + { + i_filt[c] = 512.0 * cos((3.14 * (pcjr_tint + c * 4) / 16.0) - 33.0 / 180.0); + q_filt[c] = 512.0 * sin((3.14 * (pcjr_tint + c * 4) / 16.0) - 33.0 / 180.0); + } + timer_add(pcjr_poll, &pcjr->vidtime, TIMER_ALWAYS_ENABLED, pcjr); + mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, pcjr_read, NULL, NULL, pcjr_write, NULL, NULL, NULL, 0, pcjr); + io_sethandler(0x03d0, 0x0010, pcjr_in, NULL, NULL, pcjr_out, NULL, NULL, pcjr); + overscan_x = overscan_y = 16; + return pcjr; +} + +static void pcjr_video_close(void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + + free(pcjr); +} + +static void pcjr_speed_changed(void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + + pcjr_recalctimings(pcjr); +} + +device_t pcjr_video_device = +{ + "IBM PCjr (video)", + 0, + pcjr_video_init, + pcjr_video_close, + NULL, + pcjr_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_pcjr.h b/src/vid_pcjr.h new file mode 100644 index 000000000..92bfc31e0 --- /dev/null +++ b/src/vid_pcjr.h @@ -0,0 +1 @@ +extern device_t pcjr_video_device; diff --git a/src/vid_ps1_svga.c b/src/vid_ps1_svga.c new file mode 100644 index 000000000..ca1dc01c2 --- /dev/null +++ b/src/vid_ps1_svga.c @@ -0,0 +1,189 @@ +/*Emulation of the SVGA chip in the IBM PS/1 Model 2121, or at least the + 20 MHz version. + + I am not entirely sure what this chip actually is, possibly a CF62011? I can + not find any documentation on the chip so have implemented enough to pass + self-test in the PS/1 BIOS. It has 512kb video memory but I have not found any + native drivers for any operating system and there is no VBE implementation, so + it's just a VGA for now. +*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_vga.h" + +typedef struct ps1_m2121_svga_t +{ + svga_t svga; + + rom_t bios_rom; + + uint8_t banking; + uint8_t reg_2100; + uint8_t reg_210a; +} ps1_m2121_svga_t; + +void ps1_m2121_svga_out(uint16_t addr, uint8_t val, void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + svga_t *svga = &ps1->svga; + uint8_t old; + +// pclog("svga_out : %04X %02X %04X:%04X %02X %i\n", addr, val, CS,cpu_state.pc, ram[0x489], ins); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 0x1f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x2100: + ps1->reg_2100 = val; + if ((val & 7) < 4) + svga->read_bank = svga->write_bank = 0; + else + svga->read_bank = svga->write_bank = (ps1->banking & 0x7) * 0x10000; + break; + case 0x2108: + if ((ps1->reg_2100 & 7) >= 4) + svga->read_bank = svga->write_bank = (val & 0x7) * 0x10000; + ps1->banking = val; + break; + case 0x210a: + ps1->reg_210a = val; + break; + } + svga_out(addr, val, svga); +} + +uint8_t ps1_m2121_svga_in(uint16_t addr, void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + svga_t *svga = &ps1->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("svga_in : %04X ", addr); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x100: + temp = 0xfe; + break; + case 0x101: + temp = 0xe8; + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + + case 0x2108: + temp = ps1->banking; + break; + case 0x210a: + temp = ps1->reg_210a; + break; + + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +void *ps1_m2121_svga_init() +{ + ps1_m2121_svga_t *ps1 = malloc(sizeof(ps1_m2121_svga_t)); + memset(ps1, 0, sizeof(ps1_m2121_svga_t)); + + svga_init(&ps1->svga, ps1, 1 << 19, /*512kb*/ + NULL, + ps1_m2121_svga_in, ps1_m2121_svga_out, + NULL, + NULL); + + io_sethandler(0x0100, 0x0002, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); + io_sethandler(0x03c0, 0x0020, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); + io_sethandler(0x2100, 0x0010, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); +// io_sethandler(0x210a, 0x0001, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); + + ps1->svga.bpp = 8; + ps1->svga.miscout = 1; + + return ps1; +} + +void ps1_m2121_svga_close(void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + svga_close(&ps1->svga); + + free(ps1); +} + +void ps1_m2121_svga_speed_changed(void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + svga_recalctimings(&ps1->svga); +} + +void ps1_m2121_svga_force_redraw(void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + ps1->svga.fullchange = changeframecount; +} + +void ps1_m2121_svga_add_status_info(char *s, int max_len, void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + svga_add_status_info(s, max_len, &ps1->svga); +} + +device_t ps1_m2121_svga_device = +{ + "PS/1 Model 2121 SVGA", + 0, + ps1_m2121_svga_init, + ps1_m2121_svga_close, + NULL, + ps1_m2121_svga_speed_changed, + ps1_m2121_svga_force_redraw, + ps1_m2121_svga_add_status_info +}; diff --git a/src/vid_ps1_svga.h b/src/vid_ps1_svga.h new file mode 100644 index 000000000..8cb73a9f4 --- /dev/null +++ b/src/vid_ps1_svga.h @@ -0,0 +1 @@ +extern device_t ps1_m2121_svga_device; diff --git a/src/vid_s3.c b/src/vid_s3.c new file mode 100644 index 000000000..e93befd33 --- /dev/null +++ b/src/vid_s3.c @@ -0,0 +1,2563 @@ +/*S3 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_s3.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_sdac_ramdac.h" + +enum +{ + S3_VISION864, + S3_TRIO32, + S3_TRIO64 +}; + +enum +{ + VRAM_4MB = 0, + VRAM_8MB = 3, + VRAM_2MB = 4, + VRAM_1MB = 6, + VRAM_512KB = 7 +}; + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (s3->fifo_write_idx - s3->fifo_read_idx) +#define FIFO_FULL ((s3->fifo_write_idx - s3->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (s3->fifo_read_idx == s3->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24), + FIFO_OUT_BYTE = (0x04 << 24), + FIFO_OUT_WORD = (0x05 << 24), + FIFO_OUT_DWORD = (0x06 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct s3_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + sdac_ramdac_t ramdac; + + uint8_t bank; + uint8_t ma_ext; + int width; + int bpp; + + int chip; + + uint8_t id, id_ext, id_ext_pci; + + int packed_mmio; + + uint32_t linear_base, linear_size; + + uint8_t pci_regs[256]; + + uint32_t vram_mask; + + float (*getclock)(int clock, void *p); + void *getclock_p; + + struct + { + uint8_t subsys_cntl; + uint8_t setup_md; + uint8_t advfunc_cntl; + uint16_t cur_y; + uint16_t cur_x; + int16_t desty_axstp; + int16_t destx_distp; + int16_t err_term; + int16_t maj_axis_pcnt; + uint16_t cmd; + uint16_t short_stroke; + uint32_t bkgd_color; + uint32_t frgd_color; + uint32_t wrt_mask; + uint32_t rd_mask; + uint32_t color_cmp; + uint8_t bkgd_mix; + uint8_t frgd_mix; + uint16_t multifunc_cntl; + uint16_t multifunc[16]; + uint8_t pix_trans[4]; + + int cx, cy; + int sx, sy; + int dx, dy; + uint32_t src, dest, pattern; + int pix_trans_count; + + uint32_t dat_buf; + int dat_count; + } accel; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; +} s3_t; + +void s3_updatemapping(); + +void s3_accel_write(uint32_t addr, uint8_t val, void *p); +void s3_accel_write_w(uint32_t addr, uint16_t val, void *p); +void s3_accel_write_l(uint32_t addr, uint32_t val, void *p); +uint8_t s3_accel_read(uint32_t addr, void *p); + +static inline void wake_fifo_thread(s3_t *s3) +{ + thread_set_event(s3->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void s3_wait_fifo_idle(s3_t *s3) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(s3); + thread_wait_event(s3->fifo_not_full_event, 1); + } +} + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3); + +#define WRITE8(addr, var, val) switch ((addr) & 3) \ + { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + +static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x82e8: + s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; + break; + case 0x82e9: + s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8); + break; + + case 0x86e8: + s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val; + break; + case 0x86e9: + s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8); + break; + + case 0x8ae8: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val; + break; + case 0x8ae9: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.desty_axstp |= ~0x3fff; + break; + + case 0x8ee8: + s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; + break; + case 0x8ee9: + s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.destx_distp |= ~0x3fff; + break; + + case 0x92e8: + s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val; + break; + case 0x92e9: + s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.err_term |= ~0x3fff; + break; + + case 0x96e8: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val; + break; + case 0x96e9: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3->accel.maj_axis_pcnt |= ~0x0fff; + break; + + case 0x9ae8: + s3->accel.cmd = (s3->accel.cmd & 0xff00) | val; + break; + case 0x9ae9: + s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); + s3_accel_start(-1, 0, 0xffffffff, 0, s3); + s3->accel.pix_trans_count = 0; + s3->accel.multifunc[0xe] &= ~0x10; /*hack*/ + break; + + case 0x9ee8: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; + break; + case 0x9ee9: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); + break; + + case 0xa2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; + break; + case 0xa2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa2ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + break; + case 0xa2eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + break; + + case 0xa6e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; + break; + case 0xa6e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa6ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + break; + case 0xa6eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + break; + + case 0xaae8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; + break; + case 0xaae9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xaaea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + break; + case 0xaaeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + break; + + case 0xaee8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; + break; + case 0xaee9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xaeea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + break; + case 0xaeeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + break; + + case 0xb2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; + break; + case 0xb2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xb2ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + break; + case 0xb2eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + break; + + case 0xb6e8: + s3->accel.bkgd_mix = val; + break; + + case 0xbae8: + s3->accel.frgd_mix = val; + break; + + case 0xbee8: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val; + break; + case 0xbee9: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8); + s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; + break; + + case 0xe2e8: + s3->accel.pix_trans[0] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + break; + case 0xe2e9: + s3->accel.pix_trans[1] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); + else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + break; + case 0xe2ea: + s3->accel.pix_trans[2] = val; + break; + case 0xe2eb: + s3->accel.pix_trans[3] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + break; + } +} + +static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) +{ +// pclog("Accel out w %04X %04X\n", port, val); + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } +} + +static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) +{ +// pclog("Accel out l %04X %08X\n", port, val); + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + if ((s3->accel.cmd & 0x600) == 0x400) + s3_accel_start(32, 1, val, 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(16, 1, val >> 16, 0, s3); + s3_accel_start(16, 1, val, 0, s3); + } + else if (!(s3->accel.cmd & 0x600)) + { + s3_accel_start(8, 1, val >> 24, 0, s3); + s3_accel_start(8, 1, val >> 16, 0, s3); + s3_accel_start(8, 1, val >> 8, 0, s3); + s3_accel_start(8, 1, val, 0, s3); + } + } + else + { + if ((s3->accel.cmd & 0x600) == 0x400) + s3_accel_start(4, 1, 0xffffffff, val, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + s3_accel_start(2, 1, 0xffffffff, val, s3); + } + else if (!(s3->accel.cmd & 0x600)) + { + s3_accel_start(1, 1, 0xffffffff, val >> 24, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 8, s3); + s3_accel_start(1, 1, 0xffffffff, val, s3); + } + } + } +} + +static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) +{ +// pclog("Write S3 accel %08X %02X\n", addr, val); + if (s3->packed_mmio) + { + int addr_lo = addr & 1; + switch (addr & 0xfffe) + { + case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ + case 0x8102: addr = 0x86e8; break; + + case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/ + case 0x8106: addr = 0x86ea; break; + + case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/ + case 0x810a: addr = 0x8ee8; break; + + case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/ + case 0x810e: addr = 0x8eea; break; + + case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/ + case 0x8112: addr = 0x92ee; break; + + case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/ + case 0x811a: addr = 0x9aea; break; + + case 0x811c: addr = 0x9ee8; break; /*SHORT_STROKE*/ + + case 0x8120: case 0x8122: /*BKGD_COLOR*/ + WRITE8(addr, s3->accel.bkgd_color, val); + return; + + case 0x8124: case 0x8126: /*FRGD_COLOR*/ + WRITE8(addr, s3->accel.frgd_color, val); + return; + + case 0x8128: case 0x812a: /*WRT_MASK*/ + WRITE8(addr, s3->accel.wrt_mask, val); + return; + + case 0x812c: case 0x812e: /*RD_MASK*/ + WRITE8(addr, s3->accel.rd_mask, val); + return; + + case 0x8130: case 0x8132: /*COLOR_CMP*/ + WRITE8(addr, s3->accel.color_cmp, val); + return; + + case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/ + case 0x8136: addr = 0xbae8; break; + + case 0x8138: /*SCISSORS_T*/ + WRITE8(addr & 1, s3->accel.multifunc[1], val); + return; + case 0x813a: /*SCISSORS_L*/ + WRITE8(addr & 1, s3->accel.multifunc[2], val); + return; + case 0x813c: /*SCISSORS_B*/ + WRITE8(addr & 1, s3->accel.multifunc[3], val); + return; + case 0x813e: /*SCISSORS_R*/ + WRITE8(addr & 1, s3->accel.multifunc[4], val); + return; + + case 0x8140: /*PIX_CNTL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xa], val); + return; + case 0x8142: /*MULT_MISC2*/ + WRITE8(addr & 1, s3->accel.multifunc[0xd], val); + return; + case 0x8144: /*MULT_MISC*/ + WRITE8(addr & 1, s3->accel.multifunc[0xe], val); + return; + case 0x8146: /*READ_SEL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xf], val); + return; + + case 0x8148: /*ALT_PCNT*/ + WRITE8(addr & 1, s3->accel.multifunc[0], val); + return; + case 0x814a: addr = 0x96e8; break; + case 0x814c: addr = 0x96ea; break; + + case 0x8168: addr = 0xeae8; break; + case 0x816a: addr = 0xeaea; break; + } + addr |= addr_lo; + } + + + if (addr & 0x8000) + { + s3_accel_out_fifo(s3, addr & 0xffff, val); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } + } +} + +static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) +{ +// pclog("Write S3 accel w %08X %04X\n", addr, val); + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } + } +} + +static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) +{ +// pclog("Write S3 accel l %08X %08X\n", addr, val); + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + s3_accel_write_fifo(s3, addr + 2, val >> 16); + s3_accel_write_fifo(s3, addr + 3, val >> 24); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + if ((s3->accel.cmd & 0x600) == 0x400) + s3_accel_start(32, 1, val, 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(16, 1, val >> 16, 0, s3); + s3_accel_start(16, 1, val, 0, s3); + } + else if (!(s3->accel.cmd & 0x600)) + { + s3_accel_start(8, 1, val >> 24, 0, s3); + s3_accel_start(8, 1, val >> 16, 0, s3); + s3_accel_start(8, 1, val >> 8, 0, s3); + s3_accel_start(8, 1, val, 0, s3); + } + } + else + { + if ((s3->accel.cmd & 0x600) == 0x400) + s3_accel_start(4, 1, 0xffffffff, val, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + } + else if (!(s3->accel.cmd & 0x600)) + { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 8, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 24, s3); + } + } + } + } +} + +static void fifo_thread(void *param) +{ + s3_t *s3 = (s3_t *)param; + + while (1) + { + thread_set_event(s3->fifo_not_full_event); + thread_wait_event(s3->wake_fifo_thread, -1); + thread_reset_event(s3->wake_fifo_thread); + s3->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + s3_accel_write_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + s3_accel_write_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + s3_accel_write_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_BYTE: + s3_accel_out_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_WORD: + s3_accel_out_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_DWORD: + s3_accel_out_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + s3->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(s3->fifo_not_full_event); + + end_time = timer_read(); + s3->blitter_time += end_time - start_time; + } + s3->blitter_busy = 0; + } +} + +static void s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &s3->fifo[s3->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(s3->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + s3->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(s3); +} + +void s3_out(uint16_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("S3 out %04X %02X %04x:%08x\n", addr, val, CS, pc); + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + { + svga->seqregs[svga->seqaddr] = val; + switch (svga->seqaddr) + { + case 0x12: case 0x13: + svga_recalctimings(svga); + return; + } + } + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) svga->write_bank = svga->read_bank = s3->bank << 16; + else svga->write_bank = svga->read_bank = s3->bank << 14; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc); + sdac_ramdac_out(addr, val, &s3->ramdac, svga); + return; + + case 0x3D4: + svga->crtcreg = val & 0x7f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x31: + s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4); + break; + case 0x32: + svga->vrammask = (val & 0x40) ? 0x3ffff : s3->vram_mask; + break; + + case 0x50: + switch (svga->crtc[0x50] & 0xc1) + { + case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; + case 0x01: s3->width = 1152; break; + case 0x40: s3->width = 640; break; + case 0x80: s3->width = 800; break; + case 0x81: s3->width = 1600; break; + case 0xc0: s3->width = 1280; break; + } + s3->bpp = (svga->crtc[0x50] >> 4) & 3; + break; + case 0x69: + s3->ma_ext = val & 0x1f; + break; + + case 0x35: + s3->bank = (s3->bank & 0x70) | (val & 0xf); +// pclog("CRTC write R35 %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; + else svga->write_bank = svga->read_bank = s3->bank << 14; + break; + case 0x51: + s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); +// pclog("CRTC write R51 %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; + else svga->write_bank = svga->read_bank = s3->bank << 14; + s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + s3->bank = val; +// pclog("CRTC write R6a %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; + else svga->write_bank = svga->read_bank = s3->bank << 14; + break; + + case 0x3a: + if (val & 0x10) + svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga->hwcursor.ena = val & 1; + break; + case 0x48: + svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; + if (svga->bpp == 32) svga->hwcursor.x >>= 1; + svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x4e] & 63; + svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) + svga->hwcursor.x <<= 1; + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_updatemapping(s3); + break; + + case 0x67: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + switch (val >> 4) + { + case 3: svga->bpp = 15; break; + case 5: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + case 13: svga->bpp = 32; break; + default: svga->bpp = 8; break; + } + } + break; + //case 0x55: case 0x43: +// pclog("Write CRTC R%02X %02X\n", crtcreg, val); + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t s3_in(uint16_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("S3 in %04X %08x:%02x\n", addr, CS, pc); + switch (addr) + { + case 0x3c1: + if (svga->attraddr > 0x14) + return 0xff; + break; + + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + return svga->seqregs[svga->seqaddr]; + break; + + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: +// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc); + return sdac_ramdac_in(addr, &s3->ramdac, svga); + + case 0x3d4: + return svga->crtcreg; + case 0x3d5: +// pclog("Read CRTC R%02X %02x %04X:%04X\n", svga->crtcreg, svga->crtc[svga->crtcreg], CS, pc); + switch (svga->crtcreg) + { + case 0x2d: return 0x88; /*Extended chip ID*/ + case 0x2e: return s3->id_ext; /*New chip ID*/ + case 0x2f: return 0; /*Revision level*/ + case 0x30: return s3->id; /*Chip ID*/ + case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); + case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); + case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3); + case 0x69: return s3->ma_ext; + case 0x6a: return s3->bank; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void s3_recalctimings(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + svga->hdisp = svga->hdisp_old; + +// pclog("%i %i\n", svga->hdisp, svga->hdisp_time); +// pclog("recalctimings\n"); + svga->ma_latch |= (s3->ma_ext << 16); +// pclog("SVGA_MA %08X\n", svga_ma); + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) + { + svga->hdisp_time += 0x100; + svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + } + if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; + if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + svga->interlace = svga->crtc[0x42] & 0x20; + svga->clock = cpuclock / s3->getclock((svga->miscout >> 2) & 3, s3->getclock_p); + + switch (svga->crtc[0x67] >> 4) + { + case 3: case 5: case 7: + svga->clock /= 2; + break; + } + + svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + case 32: + svga->render = svga_render_32bpp_highres; + if (s3->chip != S3_TRIO32 && s3->chip != S3_TRIO64) + svga->hdisp /= 4; + break; + } + } +} + +void s3_updatemapping(s3_t *s3) +{ + svga_t *svga = &s3->svga; + +// video_write_a000_w = video_write_a000_l = NULL; + + if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { +// pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&s3->linear_mapping); + mem_mapping_disable(&s3->mmio_mapping); + return; + } + +// pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + +// pclog("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10); + if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + mem_mapping_disable(&svga->mapping); + + s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + switch (svga->crtc[0x58] & 3) + { + case 0: /*64k*/ + s3->linear_size = 0x10000; + break; + case 1: /*1mb*/ + s3->linear_size = 0x100000; + break; + case 2: /*2mb*/ + s3->linear_size = 0x200000; + break; + case 3: /*8mb*/ + s3->linear_size = 0x800000; + break; + } + s3->linear_base &= ~(s3->linear_size - 1); +// pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]); +// pclog("Linear framebuffer at %08X size %08X\n", s3->linear_base, s3->linear_size); + if (s3->linear_base == 0xa0000) + { + mem_mapping_disable(&s3->linear_mapping); + if (!(svga->crtc[0x53] & 0x10)) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + } +// mem_mapping_set_addr(&s3->linear_mapping, 0xa0000, 0x10000); + } + else + mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); + } + else + mem_mapping_disable(&s3->linear_mapping); + +// pclog("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x10); + if (svga->crtc[0x53] & 0x10) /*Memory mapped IO*/ + { + mem_mapping_disable(&svga->mapping); + mem_mapping_enable(&s3->mmio_mapping); + } + else + mem_mapping_disable(&s3->mmio_mapping); +} + +static float s3_trio64_getclock(int clock, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + float t; + int m, n1, n2; +// pclog("Trio64_getclock %i %02X %02X\n", clock, svga->seqregs[0x13], svga->seqregs[0x12]); + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + m = svga->seqregs[0x13] + 2; + n1 = (svga->seqregs[0x12] & 0x1f) + 2; + n2 = ((svga->seqregs[0x12] >> 5) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); +// pclog("TRIO64 clock %i %i %i %f %f %i\n", m, n1, n2, t, 14318184.0 * ((float)m / (float)n1), 1 << n2); + return t; +} + + +void s3_accel_out(uint16_t port, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("Accel out %04X %02X\n", port, val); + + if (port >= 0x8000) + { + s3_queue(s3, port, val, FIFO_OUT_BYTE); + } + else switch (port) + { + case 0x42e8: + break; + case 0x42e9: + s3->accel.subsys_cntl = val; + break; + case 0x46e8: + s3->accel.setup_md = val; + break; + case 0x4ae8: + s3->accel.advfunc_cntl = val; + break; + } +} + +void s3_accel_out_w(uint16_t port, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("Accel out w %04X %04X\n", port, val); + s3_queue(s3, port, val, FIFO_OUT_WORD); +} + +void s3_accel_out_l(uint16_t port, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("Accel out l %04X %08X\n", port, val); + s3_queue(s3, port, val, FIFO_OUT_DWORD); +} + +uint8_t s3_accel_in(uint16_t port, void *p) +{ + s3_t *s3 = (s3_t *)p; + int temp; +// pclog("Accel in %04X\n", port); + switch (port) + { + case 0x42e8: + return 0; + case 0x42e9: + return 0; + + case 0x82e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y & 0xff; + case 0x82e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y >> 8; + + case 0x86e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x & 0xff; + case 0x86e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x >> 8; + + case 0x8ae8: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp & 0xff; + case 0x8ae9: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp >> 8; + + case 0x8ee8: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp & 0xff; + case 0x8ee9: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp >> 8; + + case 0x92e8: + s3_wait_fifo_idle(s3); + return s3->accel.err_term & 0xff; + case 0x92e9: + s3_wait_fifo_idle(s3); + return s3->accel.err_term >> 8; + + case 0x96e8: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt & 0xff; + case 0x96e9: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt >> 8; + + case 0x9ae8: + if (!s3->blitter_busy) + wake_fifo_thread(s3); + if (FIFO_FULL) + return 0xff; /*FIFO full*/ + return 0; /*FIFO empty*/ + case 0x9ae9: + if (!s3->blitter_busy) + wake_fifo_thread(s3); + temp = 0; + if (!FIFO_EMPTY) + temp |= 0x02; /*Hardware busy*/ + else + temp |= 0x04; /*FIFO empty*/ + if (FIFO_FULL) + temp |= 0xf8; /*FIFO full*/ + return temp; + + case 0xa2e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color & 0xff; + case 0xa2e9: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 8; + case 0xa2ea: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 16; + case 0xa2eb: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 24; + + case 0xa6e8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color & 0xff; + case 0xa6e9: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 8; + case 0xa6ea: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 16; + case 0xa6eb: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 24; + + case 0xaae8: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask & 0xff; + case 0xaae9: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 8; + case 0xaaea: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 16; + case 0xaaeb: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 24; + + case 0xaee8: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask & 0xff; + case 0xaee9: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 8; + case 0xaeea: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 16; + case 0xaeeb: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 24; + + case 0xb2e8: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp & 0xff; + case 0xb2e9: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 8; + case 0xb2ea: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 16; + case 0xb2eb: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 24; + + case 0xb6e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_mix; + + case 0xbae8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_mix; + + case 0xbee8: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] & 0xff; + case 0x1: return s3->accel.multifunc[0x1] & 0xff; + case 0x2: return s3->accel.multifunc[0x2] & 0xff; + case 0x3: return s3->accel.multifunc[0x3] & 0xff; + case 0x4: return s3->accel.multifunc[0x4] & 0xff; + case 0x5: return s3->accel.multifunc[0xa] & 0xff; + case 0x6: return s3->accel.multifunc[0xe] & 0xff; + case 0x7: return s3->accel.cmd & 0xff; + case 0x8: return s3->accel.subsys_cntl & 0xff; + case 0x9: return s3->accel.setup_md & 0xff; + case 0xa: return s3->accel.multifunc[0xd] & 0xff; + } + return 0xff; + case 0xbee9: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + s3->accel.multifunc[0xf]++; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] >> 8; + case 0x1: return s3->accel.multifunc[0x1] >> 8; + case 0x2: return s3->accel.multifunc[0x2] >> 8; + case 0x3: return s3->accel.multifunc[0x3] >> 8; + case 0x4: return s3->accel.multifunc[0x4] >> 8; + case 0x5: return s3->accel.multifunc[0xa] >> 8; + case 0x6: return s3->accel.multifunc[0xe] >> 8; + case 0x7: return s3->accel.cmd >> 8; + case 0x8: return (s3->accel.subsys_cntl >> 8) & ~0xe000; + case 0x9: return (s3->accel.setup_md >> 8) & ~0xf000; + case 0xa: return s3->accel.multifunc[0xd] >> 8; + } + return 0xff; + + case 0xe2e8: case 0xe2e9: case 0xe2ea: case 0xe2eb: /*PIX_TRANS*/ + break; + } + return 0; +} + +void s3_accel_write(uint32_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("s3_accel_write %08x %02x\n", addr, val); + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE); +} +void s3_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("s3_accel_write_w %08x %04x\n", addr, val); + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD); +} +void s3_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("s3_accel_write_l %08x %08x\n", addr, val); + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD); +} + +uint8_t s3_accel_read(uint32_t addr, void *p) +{ + if (addr & 0x8000) + return s3_accel_in(addr & 0xffff, p); + return 0; +} + +#define READ(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; + +#define MIX switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = ~0; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } + + +#define WRITE(addr) if (s3->bpp == 0) \ + { \ + svga->vram[(addr) & s3->vram_mask] = dest_dat; \ + svga->changedvram[((addr) & s3->vram_mask) >> 12] = changeframecount; \ + } \ + else if (s3->bpp == 1) \ + { \ + vram_w[(addr) & (s3->vram_mask >> 1)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ + } \ + else \ + { \ + vram_l[(addr) & (s3->vram_mask >> 2)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ + } + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) +{ + svga_t *svga = &s3->svga; + uint32_t src_dat, dest_dat; + int frgd_mix, bkgd_mix; + int clip_t = s3->accel.multifunc[1] & 0xfff; + int clip_l = s3->accel.multifunc[2] & 0xfff; + int clip_b = s3->accel.multifunc[3] & 0xfff; + int clip_r = s3->accel.multifunc[4] & 0xfff; + int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0; + uint32_t mix_mask; + uint16_t *vram_w = (uint16_t *)svga->vram; + uint32_t *vram_l = (uint32_t *)svga->vram; + uint32_t compare = s3->accel.color_cmp; + int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; +//return; +// if (!cpu_input) pclog("Start S3 command %i %i, %i %i, %i (clip %i, %i to %i, %i %i)\n", s3->accel.cmd >> 13, s3->accel.cur_x, s3->accel.cur_y, s3->accel.maj_axis_pcnt & 0xfff, s3->accel.multifunc[0] & 0xfff, clip_l, clip_t, clip_r, clip_b, s3->accel.multifunc[0xe] & 0x20); +// else pclog(" S3 command %i, %i, %08x %08x\n", s3->accel.cmd >> 13, count, mix_dat, cpu_dat); + + if (!cpu_input) s3->accel.dat_count = 0; + if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) + { + if (s3->bpp == 3 && count == 2) + { + if (s3->accel.dat_count) + { + cpu_dat = ((cpu_dat & 0xffff) << 16) | s3->accel.dat_buf; + count = 4; + s3->accel.dat_count = 0; + } + else + { + s3->accel.dat_buf = cpu_dat & 0xffff; + s3->accel.dat_count = 1; + } + } + if (s3->bpp == 1) count >>= 1; + if (s3->bpp == 3) count >>= 2; + } + + switch (s3->accel.cmd & 0x600) + { + case 0x000: mix_mask = 0x80; break; + case 0x200: mix_mask = 0x8000; break; + case 0x400: mix_mask = 0x80000000; break; + case 0x600: mix_mask = 0x80000000; break; + } + + if (s3->bpp == 0) compare &= 0xff; + if (s3->bpp == 1) compare &= 0xffff; + switch (s3->accel.cmd >> 13) + { + case 1: /*Draw line*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.sy = s3->accel.maj_axis_pcnt; + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (s3->accel.cmd & 8) /*Radial*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + if (!s3->accel.sy) + break; + + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx++; break; + case 0x20: s3->accel.cx++; s3->accel.cy--; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cx--; s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx--; s3->accel.cy++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cx++; s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + else /*Bresenham*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + +// pclog("Line : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X (%02X %02X) ", s3->accel.cx, s3->accel.cy, s3->accel.dest + s3->accel.cx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat & mix_mask, s3->accel.src + s3->accel.cx, dest_dat, s3->accel.frgd_color, s3->accel.bkgd_color); + + MIX + +// pclog("%02X\n", dest_dat); + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + +// pclog("%i, %i - %i %i %i %i\n", s3->accel.cx, s3->accel.cy, s3->accel.err_term, s3->accel.maj_axis_pcnt, s3->accel.desty_axstp, s3->accel.destx_distp); + + if (!s3->accel.sy) + break; + + if (s3->accel.err_term >= s3->accel.maj_axis_pcnt) + { + s3->accel.err_term += s3->accel.destx_distp; + /*Step minor axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cy--; break; + case 0x20: s3->accel.cy--; break; + case 0x40: s3->accel.cx--; break; + case 0x60: s3->accel.cx++; break; + case 0x80: s3->accel.cy++; break; + case 0xa0: s3->accel.cy++; break; + case 0xc0: s3->accel.cx--; break; + case 0xe0: s3->accel.cx++; break; + } + } + else + s3->accel.err_term += s3->accel.desty_axstp; + + /*Step major axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx--; break; + case 0x20: s3->accel.cx++; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + break; + + case 2: /*Rectangle fill*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.dest = s3->accel.cy * s3->width; + +// pclog("Dest %08X (%i, %i) %04X %04X\n", s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.cur_x, s3->accel.cur_x & 0x1000); + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ +// if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ +// return; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3->accel.dest + s3->accel.cx, dest_dat); + + +// if (CS != 0xc000) pclog("Write %05X %02X %02X %04X (%02X %02X) ", s3->accel.dest + s3->accel.cx, src_dat, dest_dat, mix_dat, s3->accel.frgd_mix, s3->accel.bkgd_mix); + + MIX + +// if (CS != 0xc000) pclog("%02X\n", dest_dat); + + WRITE(s3->accel.dest + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) s3->accel.cx++; + else s3->accel.cx--; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; +// s3->accel.dest -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + +// s3->accel.dest += s3_width; + if (s3->accel.cmd & 0x80) s3->accel.cy++; + else s3->accel.cy--; + + s3->accel.dest = s3->accel.cy * s3->width; + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + return; + } + } + } + break; + + case 6: /*BitBlt*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + +// pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy); + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ +// if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ +// return; + + if (s3->accel.sy < 0) + return; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && + (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7) + { + while (1) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + READ(s3->accel.src + s3->accel.cx, src_dat); + + dest_dat = src_dat; + + WRITE(s3->accel.dest + s3->accel.dx); + } + + s3->accel.cx++; + s3->accel.dx++; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + s3->accel.cy++; + s3->accel.dy++; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (s3->accel.sy < 0) + { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + return; + } + } + } + } + else + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ(s3->accel.src + s3->accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3->accel.dest + s3->accel.dx, dest_dat); + +// pclog("BitBlt : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat); + + MIX + +// pclog("%02X\n", dest_dat); + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx++; + s3->accel.dx++; + } + else + { + s3->accel.cx--; + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy++; + s3->accel.dy++; + } + else + { + s3->accel.cy--; + s3->accel.dy--; + } + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + { +// s3->accel.cur_x = s3->accel.cx; +// s3->accel.cur_y = s3->accel.cy; + return; + } + } + } + } + break; + + case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + /*Align source with destination*/ +// s3->accel.cx = (s3->accel.cx & ~7) | (s3->accel.dx & 7); +// s3->accel.cy = (s3->accel.cy & ~7) | (s3->accel.dy & 7); + + s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.cx = s3->accel.dx & 7; + s3->accel.cy = s3->accel.dy & 7; + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + +// pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy); +// dumpregs(); +// exit(-1); + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ +// if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ +// return; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ(s3->accel.src + s3->accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3->accel.dest + s3->accel.dx, dest_dat); + +// pclog("Pattern fill : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat); + + MIX + +// pclog("%02X\n", dest_dat); + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx + 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx++; + } + else + { + s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx - ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx = ((s3->accel.cx + ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy = ((s3->accel.cy + 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy++; + } + else + { + s3->accel.cy = ((s3->accel.cy - 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy--; + } + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + return; + } + } + break; + } +} + +void s3_hwcursor_draw(svga_t *svga, int displine) +{ + int x; + uint16_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; + +// pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y); + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? 0xffffff : 0; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; +// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]); + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 4; + } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + + +static void s3_io_remove(s3_t *s3) +{ + io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + +static void s3_io_set(s3_t *s3) +{ + s3_io_remove(s3); + + io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + + +uint8_t s3_pci_read(int func, int addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; +// pclog("S3 PCI read %08X\n", addr); + switch (addr) + { + case 0x00: return 0x33; /*'S3'*/ + case 0x01: return 0x53; + + case 0x02: return s3->id_ext_pci; + case 0x03: return 0x88; + + case PCI_REG_COMMAND: + return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return svga->crtc[0x5a] & 0x80; + case 0x13: return svga->crtc[0x59]; + + case 0x30: return s3->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return s3->pci_regs[0x32]; + case 0x33: return s3->pci_regs[0x33]; + } + return 0; +} + +void s3_pci_write(int func, int addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; +// pclog("s3_pci_write: addr=%02x val=%02x\n", addr, val); + switch (addr) + { + case PCI_REG_COMMAND: + if (romset == ROM_KN97) return; + s3->pci_regs[PCI_REG_COMMAND] = val & 0x27; + if (val & PCI_COMMAND_IO) + s3_io_set(s3); + else + s3_io_remove(s3); + s3_updatemapping(s3); + break; + + case 0x12: + svga->crtc[0x5a] = val & 0x80; + s3_updatemapping(s3); + break; + case 0x13: + svga->crtc[0x59] = val; + s3_updatemapping(s3); + break; + + case 0x30: case 0x32: case 0x33: + s3->pci_regs[addr] = val; + if (s3->pci_regs[0x30] & 0x01) + { + uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24); +// pclog("S3 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000); + } + else + { +// pclog("S3 bios_rom disabled\n"); + mem_mapping_disable(&s3->bios_rom.mapping); + } + return; + } +} + +static int vram_sizes[] = +{ + 7, /*512 kB*/ + 6, /*1 MB*/ + 4, /*2 MB*/ + 0, + 0, /*4 MB*/ + 0, + 0, + 0, + 3 /*8 MB*/ +}; + +static void *s3_init(char *bios_fn, int chip) +{ + s3_t *s3 = malloc(sizeof(s3_t)); + svga_t *svga = &s3->svga; + int vram; + uint32_t vram_size; + + memset(s3, 0, sizeof(s3_t)); + + vram = device_get_config_int("memory"); + if (vram) + vram_size = vram << 20; + else + vram_size = 512 << 10; + s3->vram_mask = vram_size - 1; + + rom_init(&s3->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&s3->bios_rom.mapping); + + mem_mapping_add(&s3->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &s3->svga); + mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3); + mem_mapping_disable(&s3->mmio_mapping); + + svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/ + s3_recalctimings, + s3_in, s3_out, + s3_hwcursor_draw, + NULL); + + if (PCI) + svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + else + svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + svga->crtc[0x37] = 1 | (7 << 5); + + s3_io_set(s3); + + pci_add(s3_pci_read, s3_pci_write, s3); + + s3->pci_regs[0x04] = 7; + + s3->pci_regs[0x30] = 0x00; + s3->pci_regs[0x32] = 0x0c; + s3->pci_regs[0x33] = 0x00; + + s3->chip = chip; + + s3->wake_fifo_thread = thread_create_event(); + s3->fifo_not_full_event = thread_create_event(); + s3->fifo_thread = thread_create(fifo_thread, s3); + + return s3; +} + +void *s3_bahamas64_init() +{ + s3_t *s3 = s3_init("roms/bahamas64.BIN", S3_VISION864); + + s3->id = 0xc1; /*Vision864P*/ + s3->id_ext = s3->id_ext_pci = 0xc1; + s3->packed_mmio = 0; + + s3->getclock = sdac_getclock; + s3->getclock_p = &s3->ramdac; + + return s3; +} + +int s3_bahamas64_available() +{ + return rom_present("roms/bahamas64.BIN"); +} + +void *s3_9fx_init() +{ + s3_t *s3 = s3_init("roms/s3_764.bin", S3_TRIO64); + + s3->id = 0xe1; /*Trio64*/ + s3->id_ext = s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +int s3_9fx_available() +{ + return rom_present("roms/s3_764.bin"); +} + +void *s3_phoenix_trio32_init() +{ + s3_t *s3 = s3_init("roms/86C732P.bin", S3_TRIO32); + svga_t *svga = &s3->svga; + + s3->id = 0xe1; /*Trio32*/ + s3->id_ext = 0x10; + s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +int s3_phoenix_trio32_available() +{ + return rom_present("roms/86C732P.bin"); +} + +void *s3_phoenix_trio64_init() +{ + s3_t *s3 = s3_init("roms/86c764x1.bin", S3_TRIO64); + svga_t *svga = &s3->svga; + + s3->id = 0xe1; /*Trio64*/ + s3->id_ext = s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +int s3_phoenix_trio64_available() +{ + return rom_present("roms/86c764x1.bin"); +} + +void *s3_miro_vision964_init() +{ + s3_t *s3 = s3_init("roms/VISION864P.BIN", S3_VISION864); + + s3->id = 0xc1; /*Vision864P*/ + s3->id_ext = s3->id_ext_pci = 0xc1; + s3->packed_mmio = 1; + + s3->getclock = sdac_getclock; + s3->getclock_p = &s3->ramdac; + + return s3; +} + +int s3_miro_vision964_available() +{ + return rom_present("roms/VISION864P.BIN"); +} + +void s3_close(void *p) +{ + s3_t *s3 = (s3_t *)p; + + svga_close(&s3->svga); + + free(s3); +} + +void s3_speed_changed(void *p) +{ + s3_t *s3 = (s3_t *)p; + + svga_recalctimings(&s3->svga); +} + +void s3_force_redraw(void *p) +{ + s3_t *s3 = (s3_t *)p; + + s3->svga.fullchange = changeframecount; +} + +void s3_add_status_info(char *s, int max_len, void *p) +{ + s3_t *s3 = (s3_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - s3->status_time; + s3->status_time = new_time; + + if (!status_diff) + status_diff = 1; + + svga_add_status_info(s, max_len, &s3->svga); + sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)s3->blitter_time * 100.0) / timer_freq, ((double)s3->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + s3->blitter_time = 0; +} + +static device_config_t s3_bahamas64_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/ + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +static device_config_t s3_9fx_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static device_config_t s3_phoenix_trio32_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "512 KB", + .value = 0 + }, + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static device_config_t s3_phoenix_trio64_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "512 KB", + .value = 0 + }, + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static device_config_t s3_miro_vision964_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "3 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "6 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/ + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +device_t s3_bahamas64_device = +{ + "Paradise Bahamas 64 (S3 Vision864)", + 0, + s3_bahamas64_init, + s3_close, + s3_bahamas64_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_bahamas64_config +}; + +device_t s3_9fx_device = +{ + "Number 9 9FX (S3 Trio64)", + 0, + s3_9fx_init, + s3_close, + s3_9fx_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_9fx_config +}; + +device_t s3_phoenix_trio32_device = +{ + "Phoenix S3 Trio32", + 0, + s3_phoenix_trio32_init, + s3_close, + s3_phoenix_trio32_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_phoenix_trio32_config +}; + +device_t s3_phoenix_trio64_device = +{ + "Phoenix S3 Trio64", + 0, + s3_phoenix_trio64_init, + s3_close, + s3_phoenix_trio64_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_phoenix_trio64_config +}; + +device_t s3_miro_vision964_device = +{ + "Micro Crystal S3 Vision964", + 0, + s3_miro_vision964_init, + s3_close, + s3_miro_vision964_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_miro_vision964_config +}; diff --git a/src/vid_s3.h b/src/vid_s3.h new file mode 100644 index 000000000..fe10bf7be --- /dev/null +++ b/src/vid_s3.h @@ -0,0 +1,5 @@ +device_t s3_bahamas64_device; +device_t s3_9fx_device; +device_t s3_phoenix_trio32_device; +device_t s3_phoenix_trio64_device; +device_t s3_miro_vision964_device; diff --git a/src/vid_s3_virge.c b/src/vid_s3_virge.c new file mode 100644 index 000000000..fe0cb1f09 --- /dev/null +++ b/src/vid_s3_virge.c @@ -0,0 +1,4071 @@ +/*S3 ViRGE emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_s3_virge.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +static uint64_t virge_time = 0; +static uint64_t status_time = 0; +static int reg_writes = 0, reg_reads = 0; + +static int dither[4][4] = +{ + 0, 4, 1, 5, + 6, 2, 7, 3, + 1, 5, 0, 4, + 7, 3, 6, 2, +}; + +#define RB_SIZE 256 +#define RB_MASK (RB_SIZE - 1) + +#define RB_ENTRIES (virge->s3d_write_idx - virge->s3d_read_idx) +#define RB_FULL (RB_ENTRIES == RB_SIZE) +#define RB_EMPTY (!RB_ENTRIES) + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (virge->fifo_write_idx - virge->fifo_read_idx) +#define FIFO_FULL ((virge->fifo_write_idx - virge->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (virge->fifo_read_idx == virge->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24), +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct s3d_t +{ + uint32_t cmd_set; + int clip_l, clip_r, clip_t, clip_b; + + uint32_t dest_base; + uint32_t dest_str; + + uint32_t z_base; + uint32_t z_str; + + uint32_t tex_base; + uint32_t tex_bdr_clr; + uint32_t tbv, tbu; + int32_t TdVdX, TdUdX; + int32_t TdVdY, TdUdY; + uint32_t tus, tvs; + + int32_t TdZdX, TdZdY; + uint32_t tzs; + + int32_t TdWdX, TdWdY; + uint32_t tws; + + int32_t TdDdX, TdDdY; + uint32_t tds; + + int16_t TdGdX, TdBdX, TdRdX, TdAdX; + int16_t TdGdY, TdBdY, TdRdY, TdAdY; + uint32_t tgs, tbs, trs, tas; + + uint32_t TdXdY12; + uint32_t txend12; + uint32_t TdXdY01; + uint32_t txend01; + uint32_t TdXdY02; + uint32_t txs; + uint32_t tys; + int ty01, ty12, tlr; +} s3d_t; + +typedef struct virge_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + mem_mapping_t new_mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + + uint8_t bank; + uint8_t ma_ext; + int width; + int bpp; + + uint8_t virge_id, virge_id_high, virge_id_low, virge_rev; + + uint32_t linear_base, linear_size; + + uint8_t pci_regs[256]; + + int is_375; + + int bilinear_enabled; + int dithering_enabled; + int memory_size; + + int pixel_count, tri_count; + + thread_t *render_thread; + event_t *wake_render_thread; + event_t *wake_main_thread; + event_t *not_full_event; + + uint32_t hwcursor_col[2]; + int hwcursor_col_pos; + + struct + { + uint32_t src_base; + uint32_t dest_base; + int clip_l, clip_r, clip_t, clip_b; + int dest_str, src_str; + uint32_t mono_pat_0; + uint32_t mono_pat_1; + uint32_t pat_bg_clr; + uint32_t pat_fg_clr; + uint32_t src_bg_clr; + uint32_t src_fg_clr; + uint32_t cmd_set; + int r_width, r_height; + int rsrc_x, rsrc_y; + int rdest_x, rdest_y; + + int lxend0, lxend1; + int32_t ldx; + uint32_t lxstart, lystart; + int lycnt; + int line_dir; + + int src_x, src_y; + int dest_x, dest_y; + int w, h; + uint8_t rop; + + int data_left_count; + uint32_t data_left; + + uint32_t pattern_8[8*8]; + uint32_t pattern_16[8*8]; + uint32_t pattern_32[8*8]; + + uint32_t prdx; + uint32_t prxstart; + uint32_t pldx; + uint32_t plxstart; + uint32_t pystart; + uint32_t pycnt; + uint32_t dest_l, dest_r; + } s3d; + + s3d_t s3d_tri; + + s3d_t s3d_buffer[RB_SIZE]; + int s3d_read_idx, s3d_write_idx; + int s3d_busy; + + struct + { + uint32_t pri_ctrl; + uint32_t chroma_ctrl; + uint32_t sec_ctrl; + uint32_t chroma_upper_bound; + uint32_t sec_filter; + uint32_t blend_ctrl; + uint32_t pri_fb0, pri_fb1; + uint32_t pri_stride; + uint32_t buffer_ctrl; + uint32_t sec_fb0, sec_fb1; + uint32_t sec_stride; + uint32_t overlay_ctrl; + int32_t k1_vert_scale; + int32_t k2_vert_scale; + int32_t dda_vert_accumulator; + int32_t k1_horiz_scale; + int32_t k2_horiz_scale; + int32_t dda_horiz_accumulator; + uint32_t fifo_ctrl; + uint32_t pri_start; + uint32_t pri_size; + uint32_t sec_start; + uint32_t sec_size; + + int sdif; + + int pri_x, pri_y, pri_w, pri_h; + int sec_x, sec_y, sec_w, sec_h; + } streams; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int virge_busy; +} virge_t; + +static inline void wake_fifo_thread(virge_t *virge) +{ + thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void queue_triangle(virge_t *virge); + +static void s3_virge_recalctimings(svga_t *svga); +static void s3_virge_updatemapping(virge_t *virge); + +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); + +static uint8_t s3_virge_mmio_read(uint32_t addr, void *p); +static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p); +static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p); +static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p); +static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p); +static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p); + +enum +{ + CMD_SET_AE = 1, + CMD_SET_HC = (1 << 1), + + CMD_SET_FORMAT_MASK = (7 << 2), + CMD_SET_FORMAT_8 = (0 << 2), + CMD_SET_FORMAT_16 = (1 << 2), + CMD_SET_FORMAT_24 = (2 << 2), + + CMD_SET_MS = (1 << 6), + CMD_SET_IDS = (1 << 7), + CMD_SET_MP = (1 << 8), + CMD_SET_TP = (1 << 9), + + CMD_SET_ITA_MASK = (3 << 10), + CMD_SET_ITA_BYTE = (0 << 10), + CMD_SET_ITA_WORD = (1 << 10), + CMD_SET_ITA_DWORD = (2 << 10), + + CMD_SET_ZUP = (1 << 23), + + CMD_SET_ZB_MODE = (3 << 24), + + CMD_SET_XP = (1 << 25), + CMD_SET_YP = (1 << 26), + + CMD_SET_COMMAND_MASK = (15 << 27) +}; + +#define CMD_SET_ABC_SRC (1 << 18) +#define CMD_SET_ABC_ENABLE (1 << 19) +#define CMD_SET_TWE (1 << 26) + +enum +{ + CMD_SET_COMMAND_BITBLT = (0 << 27), + CMD_SET_COMMAND_RECTFILL = (2 << 27), + CMD_SET_COMMAND_LINE = (3 << 27), + CMD_SET_COMMAND_POLY = (5 << 27), + CMD_SET_COMMAND_NOP = (15 << 27) +}; + +static void s3_virge_out(uint16_t addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("S3 out %04X %02X %04X:%08X %04X %04X %i\n", addr, val, CS, pc, ES, BX, ins); + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr >= 0x10) + { + svga->seqregs[svga->seqaddr & 0x1f]=val; + svga_recalctimings(svga); + return; + } + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + } + break; + + //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc); + //sdac_ramdac_out(addr,val); + //return; + + case 0x3d4: + svga->crtcreg = val;// & 0x7f; + return; + case 0x3d5: + //pclog("Write CRTC R%02X %02X %04x(%08x):%08x\n", svga->crtcreg, val, CS, cs, pc); + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) + return; + if (svga->crtcreg >= 0x80) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x31: + virge->ma_ext = (virge->ma_ext & 0x1c) | ((val & 0x30) >> 4); + break; + case 0x32: + if ((svga->crtc[0x67] & 0xc) != 0xc) + svga->vrammask = (val & 0x40) ? 0x3ffff : ((virge->memory_size << 20) - 1); + break; + + case 0x50: + switch (svga->crtc[0x50] & 0xc1) + { + case 0x00: virge->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; + case 0x01: virge->width = 1152; break; + case 0x40: virge->width = 640; break; + case 0x80: virge->width = 800; break; + case 0x81: virge->width = 1600; break; + case 0xc0: virge->width = 1280; break; + } + virge->bpp = (svga->crtc[0x50] >> 4) & 3; + break; + case 0x69: + virge->ma_ext = val & 0x1f; + break; + + case 0x35: + virge->bank = (virge->bank & 0x70) | (val & 0xf); +// pclog("CRTC write R35 %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + break; + case 0x51: + virge->bank = (virge->bank & 0x4f) | ((val & 0xc) << 2); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + virge->ma_ext = (virge->ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + virge->bank = val; +// pclog("CRTC write R6a %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + break; + + case 0x3a: + if (val & 0x10) svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga->hwcursor.ena = val & 1; + break; + case 0x46: case 0x47: case 0x48: case 0x49: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; + svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x4e] & 63; + svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + break; + + case 0x4a: + virge->hwcursor_col[1] = (virge->hwcursor_col[1] & ~(0xff << (virge->hwcursor_col_pos * 8))) | + (val << (virge->hwcursor_col_pos * 8)); + virge->hwcursor_col_pos++; + virge->hwcursor_col_pos &= 3; + break; + case 0x4b: + virge->hwcursor_col[0] = (virge->hwcursor_col[0] & ~(0xff << (virge->hwcursor_col_pos * 8))) | + (val << (virge->hwcursor_col_pos * 8)); + virge->hwcursor_col_pos++; + virge->hwcursor_col_pos &= 3; + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_virge_updatemapping(virge); + break; + + case 0x67: + switch (val >> 4) + { + case 3: svga->bpp = 15; break; + case 5: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + case 13: svga->bpp = 32; break; + default: svga->bpp = 8; break; + } + break; + //case 0x55: case 0x43: +// pclog("Write CRTC R%02X %02X\n", crtcreg, val); + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +static uint8_t s3_virge_in(uint16_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t ret; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("S3 in %04X %04X:%08X ", addr, CS, pc); + switch (addr) + { + case 0x3c1: + if (svga->attraddr > 0x14) + ret = 0xff; + else + ret = svga_in(addr, svga); + break; + //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc); + //return sdac_ramdac_in(addr); + + case 0x3c5: + if (svga->seqaddr >= 8) + ret = svga->seqregs[svga->seqaddr & 0x1f]; + else if (svga->seqaddr <= 4) + ret = svga_in(addr, svga); + else + ret = 0xff; + break; + + case 0x3D4: + ret = svga->crtcreg; + break; + case 0x3D5: + //pclog("Read CRTC R%02X %04X:%04X (%02x)\n", svga->crtcreg, CS, pc, svga->crtc[svga->crtcreg]); + switch (svga->crtcreg) + { + case 0x2d: ret = virge->virge_id_high; break; /*Extended chip ID*/ + case 0x2e: ret = virge->virge_id_low; break; /*New chip ID*/ + case 0x2f: ret = virge->virge_rev; break; + case 0x30: ret = virge->virge_id; break; /*Chip ID*/ + case 0x31: ret = (svga->crtc[0x31] & 0xcf) | ((virge->ma_ext & 3) << 4); break; + case 0x35: ret = (svga->crtc[0x35] & 0xf0) | (virge->bank & 0xf); break; + case 0x36: ret = (svga->crtc[0x36] & 0xfc) | 2; break; /*PCI bus*/ + case 0x45: virge->hwcursor_col_pos = 0; ret = svga->crtc[0x45]; break; + case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); break; + case 0x69: ret = virge->ma_ext; break; + case 0x6a: ret = virge->bank; break; + default: ret = svga->crtc[svga->crtcreg]; break; + } + break; + + default: + ret = svga_in(addr, svga); + break; + } +// if (addr != 0x3da) pclog("%02X\n", ret); + return ret; +} + +static void s3_virge_recalctimings(svga_t *svga) +{ + virge_t *virge = (virge_t *)svga->p; + + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) svga->hdisp += 0x100; + if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; + svga->interlace = svga->crtc[0x42] & 0x20; + + if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ + { + svga->ma_latch |= (virge->ma_ext << 16); +//pclog("VGA mode\n"); + if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; + } + } + +// pclog("svga->rowoffset = %i bpp=%i\n", svga->rowoffset, svga->bpp); + if (svga->bpp == 15 || svga->bpp == 16) + { + svga->htotal >>= 1; + svga->hdisp >>= 1; + } + if (svga->bpp == 24) + { + svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ + } + svga->vrammask = (svga->crtc[0x32] & 0x40) ? 0x3ffff : ((virge->memory_size << 20) - 1); +//pclog("VGA mode x_disp=%i dispend=%i vtotal=%i\n", svga->hdisp, svga->dispend, svga->vtotal); + } + else /*Streams mode*/ + { + if (virge->streams.buffer_ctrl & 1) + svga->ma_latch = virge->streams.pri_fb1 >> 2; + else + svga->ma_latch = virge->streams.pri_fb0 >> 2; + + svga->hdisp = virge->streams.pri_w + 1; + if (virge->streams.pri_h < svga->dispend) + svga->dispend = virge->streams.pri_h; + + svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; + svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; + svga->overlay.ysize = virge->streams.sec_h; + + if (virge->streams.buffer_ctrl & 2) + svga->overlay.addr = virge->streams.sec_fb1; + else + svga->overlay.addr = virge->streams.sec_fb0; + + svga->overlay.ena = (svga->overlay.x >= 0); + svga->overlay.v_acc = virge->streams.dda_vert_accumulator; +//pclog("Streams mode x_disp=%i dispend=%i vtotal=%i x=%i y=%i ysize=%i\n", svga->hdisp, svga->dispend, svga->vtotal, svga->overlay.x, svga->overlay.y, svga->overlay.ysize); + svga->rowoffset = virge->streams.pri_stride >> 3; + + switch ((virge->streams.pri_ctrl >> 24) & 0x7) + { + case 0: /*RGB-8 (CLUT)*/ + svga->render = svga_render_8bpp_highres; + break; + case 3: /*KRGB-16 (1.5.5.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_15bpp_highres; + break; + case 5: /*RGB-16 (5.6.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_16bpp_highres; + break; + case 6: /*RGB-24 (8.8.8)*/ + svga->render = svga_render_24bpp_highres; + break; + case 7: /*XRGB-32 (X.8.8.8)*/ + svga->render = svga_render_32bpp_highres; + break; + } + svga->vrammask = (virge->memory_size << 20) - 1; + } + + if (((svga->miscout >> 2) & 3) == 3) + { + int n = svga->seqregs[0x12] & 0x1f; + int r = (svga->seqregs[0x12] >> 5) & (virge->is_375 ? 7 : 3); + int m = svga->seqregs[0x13] & 0x7f; + double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; + + svga->clock = cpuclock / freq; + } +} + +static void s3_virge_updatemapping(virge_t *virge) +{ + svga_t *svga = &virge->svga; + + if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { +// pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&virge->linear_mapping); + mem_mapping_disable(&virge->mmio_mapping); + mem_mapping_disable(&virge->new_mmio_mapping); + return; + } + + pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + virge->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + + pclog("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10); + if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + switch (svga->crtc[0x58] & 3) + { + case 0: /*64k*/ + virge->linear_size = 0x10000; + break; + case 1: /*1mb*/ + virge->linear_size = 0x100000; + break; + case 2: /*2mb*/ + virge->linear_size = 0x200000; + break; + case 3: /*8mb*/ + virge->linear_size = 0x400000; + break; + } + virge->linear_base &= ~(virge->linear_size - 1); +// pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]); + pclog("Linear framebuffer at %08X size %08X\n", virge->linear_base, virge->linear_size); + if (virge->linear_base == 0xa0000) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&virge->linear_mapping); + } + else + mem_mapping_set_addr(&virge->linear_mapping, virge->linear_base, virge->linear_size); + svga->fb_only = 1; + } + else + { + mem_mapping_disable(&virge->linear_mapping); + svga->fb_only = 0; + } + + pclog("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x18); + if (svga->crtc[0x53] & 0x10) /*Old MMIO*/ + { + if (svga->crtc[0x53] & 0x20) + mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000); + else + mem_mapping_set_addr(&virge->mmio_mapping, 0xa0000, 0x10000); + } + else + mem_mapping_disable(&virge->mmio_mapping); + + if (svga->crtc[0x53] & 0x08) /*New MMIO*/ + mem_mapping_set_addr(&virge->new_mmio_mapping, virge->linear_base + 0x1000000, 0x10000); + else + mem_mapping_disable(&virge->new_mmio_mapping); + +} + +static void s3_virge_wait_fifo_idle(virge_t *virge) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(virge); + thread_wait_event(virge->fifo_not_full_event, 1); + } +} + +static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + uint8_t ret; + + reg_reads++; +// pclog("New MMIO readb %08X\n", addr); + switch (addr & 0xffff) + { + case 0x8505: + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) + ret = 0x10; + else + ret = 0x10 | (1 << 5); + if (!virge->virge_busy) + wake_fifo_thread(virge); + return ret; + + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + return s3_virge_in(addr & 0x3ff, p); + } + return 0xff; +} +static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p) +{ + reg_reads++; +// pclog("New MMIO readw %08X\n", addr); + switch (addr & 0xfffe) + { + default: + return s3_virge_mmio_read(addr, p) | (s3_virge_mmio_read(addr + 1, p) << 8); + } + return 0xffff; +} +static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + uint32_t ret = 0xffffffff; + reg_reads++; +// pclog("New MMIO readl %08X %04X(%08X):%08X ", addr, CS, cs, pc); + switch (addr & 0xfffc) + { + case 0x8180: + ret = virge->streams.pri_ctrl; + break; + case 0x8184: + ret = virge->streams.chroma_ctrl; + break; + case 0x8190: + ret = virge->streams.sec_ctrl; + break; + case 0x8194: + ret = virge->streams.chroma_upper_bound; + break; + case 0x8198: + ret = virge->streams.sec_filter; + break; + case 0x81a0: + ret = virge->streams.blend_ctrl; + break; + case 0x81c0: + ret = virge->streams.pri_fb0; + break; + case 0x81c4: + ret = virge->streams.pri_fb1; + break; + case 0x81c8: + ret = virge->streams.pri_stride; + break; + case 0x81cc: + ret = virge->streams.buffer_ctrl; + break; + case 0x81d0: + ret = virge->streams.sec_fb0; + break; + case 0x81d4: + ret = virge->streams.sec_fb1; + break; + case 0x81d8: + ret = virge->streams.sec_stride; + break; + case 0x81dc: + ret = virge->streams.overlay_ctrl; + break; + case 0x81e0: + ret = virge->streams.k1_vert_scale; + break; + case 0x81e4: + ret = virge->streams.k2_vert_scale; + break; + case 0x81e8: + ret = virge->streams.dda_vert_accumulator; + break; + case 0x81ec: + ret = virge->streams.fifo_ctrl; + break; + case 0x81f0: + ret = virge->streams.pri_start; + break; + case 0x81f4: + ret = virge->streams.pri_size; + break; + case 0x81f8: + ret = virge->streams.sec_start; + break; + case 0x81fc: + ret = virge->streams.sec_size; + break; + + case 0x8504: + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) + ret = (0x10 << 8); + else + ret = (0x10 << 8) | (1 << 13); + if (!virge->virge_busy) + wake_fifo_thread(virge); +// pclog("Read status %04x %i\n", ret, virge->s3d_busy); + break; + case 0xa4d4: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_base; + break; + case 0xa4d8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.dest_base; + break; + case 0xa4dc: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r; + break; + case 0xa4e0: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b; + break; + case 0xa4e4: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str; + break; + case 0xa4e8: case 0xace8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.mono_pat_0; + break; + case 0xa4ec: case 0xacec: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.mono_pat_1; + break; + case 0xa4f0: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.pat_bg_clr; + break; + case 0xa4f4: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.pat_fg_clr; + break; + case 0xa4f8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_bg_clr; + break; + case 0xa4fc: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_fg_clr; + break; + case 0xa500: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.cmd_set; + break; + case 0xa504: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.r_width << 16) | virge->s3d.r_height; + break; + case 0xa508: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y; + break; + case 0xa50c: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y; + break; + + default: + ret = s3_virge_mmio_read_w(addr, p) | (s3_virge_mmio_read_w(addr + 2, p) << 16); + } +// /*if ((addr & 0xfffc) != 0x8504) */pclog("%02x\n", ret); + return ret; +} + +static void fifo_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (1) + { + thread_set_event(virge->fifo_not_full_event); + thread_wait_event(virge->wake_fifo_thread, -1); + thread_reset_event(virge->wake_fifo_thread); + virge->virge_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + s3_virge_bitblt(virge, 8, val); + break; + case FIFO_WRITE_WORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); + else + s3_virge_bitblt(virge, 16, val); + } + break; + case FIFO_WRITE_DWORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + } + else + { + switch ((fifo->addr_type & FIFO_ADDR) & 0xfffc) + { + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = (fifo->addr_type & FIFO_ADDR) & 4; + int y = ((fifo->addr_type & FIFO_ADDR) >> 3) & 7; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = ((fifo->addr_type & FIFO_ADDR) >> 1) & 6; + y = ((fifo->addr_type & FIFO_ADDR) >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + x = ((fifo->addr_type & FIFO_ADDR) >> 2) & 7; + y = ((fifo->addr_type & FIFO_ADDR) >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = val & 0x3ffff8; + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = val & 0x3ffff8; + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb4d4: + virge->s3d_tri.z_base = val & 0x3ffff8; + break; + case 0xb4d8: + virge->s3d_tri.dest_base = val & 0x3ffff8; + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = val & 0x3ffff8; + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) + queue_triangle(virge); + break; + } + } + break; + } + + virge->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(virge->fifo_not_full_event); + + end_time = timer_read(); + virge_time += end_time - start_time; + } + virge->virge_busy = 0; + } +} + +static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(virge->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(virge->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + virge->fifo_write_idx++; + + /* if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(virge); */ + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(virge); +} + +static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + +// pclog("New MMIO writeb %08X %02X %04x(%08x):%08x\n", addr, val, CS, cs, pc); + reg_writes++; + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0xffff) + { + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + s3_virge_out(addr & 0x3ff, val, p); + break; + } + + +} +static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + reg_writes++; +// pclog("New MMIO writew %08X %04X %04x(%08x):%08x\n", addr, val, CS, cs, pc); + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD); + } + else switch (addr & 0xfffe) + { + case 0x83d4: + s3_virge_mmio_write(addr, val, p); + s3_virge_mmio_write(addr + 1, val >> 8, p); + break; + } +} +static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + reg_writes++; +// if ((addr & 0xfffc) >= 0xb400 && (addr & 0xfffc) < 0xb800) +// pclog("New MMIO writel %08X %08X %04x(%08x):%08x\n", addr, val, CS, cs, pc); + + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); + } + else if ((addr & 0xe000) == 0xa000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); + } + else switch (addr & 0xfffc) + { + case 0x8180: + virge->streams.pri_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x8184: + virge->streams.chroma_ctrl = val; + break; + case 0x8190: + virge->streams.sec_ctrl = val; + virge->streams.dda_horiz_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_horiz_accumulator |= 0xfffff800; + virge->streams.sdif = (val >> 24) & 7; + break; + case 0x8194: + virge->streams.chroma_upper_bound = val; + break; + case 0x8198: + virge->streams.sec_filter = val; + virge->streams.k1_horiz_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_horiz_scale |= 0xfffff800; + virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff; + if ((val >> 16) & (1 << 10)) + virge->streams.k2_horiz_scale |= 0xfffff800; + break; + case 0x81a0: + virge->streams.blend_ctrl = val; + break; + case 0x81c0: +// pclog("Write pri_fb0 %08x\n", val); + virge->streams.pri_fb0 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c4: +// pclog("Write pri_fb1 %08x\n", val); + virge->streams.pri_fb1 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c8: + virge->streams.pri_stride = val & 0xfff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81cc: +// pclog("Write buffer_ctrl %08x\n", val); + virge->streams.buffer_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d0: + virge->streams.sec_fb0 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d4: + virge->streams.sec_fb1 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d8: + virge->streams.sec_stride = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81dc: + virge->streams.overlay_ctrl = val; + break; + case 0x81e0: + virge->streams.k1_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_vert_scale |= 0xfffff800; + break; + case 0x81e4: + virge->streams.k2_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k2_vert_scale |= 0xfffff800; + break; + case 0x81e8: + virge->streams.dda_vert_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_vert_accumulator |= 0xfffff800; + break; + case 0x81ec: + virge->streams.fifo_ctrl = val; + break; + case 0x81f0: + virge->streams.pri_start = val; + virge->streams.pri_x = (val >> 16) & 0x7ff; + virge->streams.pri_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f4: + virge->streams.pri_size = val; + virge->streams.pri_w = (val >> 16) & 0x7ff; + virge->streams.pri_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f8: + virge->streams.sec_start = val; + virge->streams.sec_x = (val >> 16) & 0x7ff; + virge->streams.sec_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81fc: + virge->streams.sec_size = val; + virge->streams.sec_w = (val >> 16) & 0x7ff; + virge->streams.sec_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = addr & 4; + int y = (addr >> 3) & 7; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = (addr >> 1) & 6; + y = (addr >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + x = (addr >> 2) & 7; + y = (addr >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = val & 0x3ffff8; + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = val & 0x3ffff8; + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb4d4: + virge->s3d_tri.z_base = val & 0x3ffff8; + break; + case 0xb4d8: + virge->s3d_tri.dest_base = val & 0x3ffff8; + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = val & 0x3ffff8; + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); +/* { + thread_set_event(virge->wake_render_thread); + thread_wait_event(virge->wake_main_thread, -1); + } */ +// s3_virge_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) + queue_triangle(virge); +/* { + thread_set_event(virge->wake_render_thread); + thread_wait_event(virge->wake_main_thread, -1); + }*/ + +// s3_virge_triangle(virge); + break; + } +} + +#define READ(addr, val) \ + do \ + { \ + switch (bpp) \ + { \ + case 0: /*8 bpp*/ \ + val = vram[addr & 0x3fffff]; \ + break; \ + case 1: /*16 bpp*/ \ + val = *(uint16_t *)&vram[addr & 0x3fffff]; \ + break; \ + case 2: /*24 bpp*/ \ + val = (*(uint32_t *)&vram[addr & 0x3fffff]) & 0xffffff; \ + break; \ + } \ + } while (0) + +#define Z_READ(addr) *(uint16_t *)&vram[addr & 0x3fffff] + +#define Z_WRITE(addr, val) if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) *(uint16_t *)&vram[addr & 0x3fffff] = val + +#define CLIP(x, y) \ + do \ + { \ + if ((virge->s3d.cmd_set & CMD_SET_HC) && \ + (x < virge->s3d.clip_l || \ + x > virge->s3d.clip_r || \ + y < virge->s3d.clip_t || \ + y > virge->s3d.clip_b)) \ + update = 0; \ + } while (0) + +#define CLIP_3D(x, y) \ + do \ + { \ + if ((s3d_tri->cmd_set & CMD_SET_HC) && \ + (x < s3d_tri->clip_l || \ + x > s3d_tri->clip_r || \ + y < s3d_tri->clip_t || \ + y > s3d_tri->clip_b)) \ + update = 0; \ + } while (0) + +#define Z_CLIP(Zzb, Zs) \ + do \ + { \ + if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ + switch ((s3d_tri->cmd_set >> 20) & 7) \ + { \ + case 0: update = 0; break; \ + case 1: if (Zs <= Zzb) update = 0; else Zzb = Zs; break; \ + case 2: if (Zs != Zzb) update = 0; else Zzb = Zs; break; \ + case 3: if (Zs < Zzb) update = 0; else Zzb = Zs; break; \ + case 4: if (Zs >= Zzb) update = 0; else Zzb = Zs; break; \ + case 5: if (Zs == Zzb) update = 0; else Zzb = Zs; break; \ + case 6: if (Zs > Zzb) update = 0; else Zzb = Zs; break; \ + case 7: update = 1; Zzb = Zs; break; \ + } \ + } while (0) + +#define MIX() \ + do \ + { \ + int c; \ + for (c = 0; c < 24; c++) \ + { \ + int d = (dest & (1 << c)) ? 1 : 0; \ + if (source & (1 << c)) d |= 2; \ + if (pattern & (1 << c)) d |= 4; \ + if (virge->s3d.rop & (1 << d)) out |= (1 << c); \ + } \ + } while (0) + +#define WRITE(addr, val) \ + do \ + { \ + switch (bpp) \ + { \ + case 0: /*8 bpp*/ \ + vram[addr & 0x3fffff] = val; \ + virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \ + break; \ + case 1: /*16 bpp*/ \ + *(uint16_t *)&vram[addr & 0x3fffff] = val; \ + virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \ + break; \ + case 2: /*24 bpp*/ \ + *(uint32_t *)&vram[addr & 0x3fffff] = (val & 0xffffff) | \ + (vram[(addr + 3) & 0x3fffff] << 24); \ + virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \ + break; \ + } \ + } while (0) + +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) +{ + int cpu_input = (count != -1); + uint8_t *vram = virge->svga.vram; + uint32_t mono_pattern[64]; + int count_mask; + int x_inc = (virge->s3d.cmd_set & CMD_SET_XP) ? 1 : -1; + int y_inc = (virge->s3d.cmd_set & CMD_SET_YP) ? 1 : -1; + int bpp; + int x_mul; + int cpu_dat_shift; + uint32_t *pattern_data; + + switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) + { + case CMD_SET_FORMAT_8: + bpp = 0; + x_mul = 1; + cpu_dat_shift = 8; + pattern_data = virge->s3d.pattern_8; + break; + case CMD_SET_FORMAT_16: + bpp = 1; + x_mul = 2; + cpu_dat_shift = 16; + pattern_data = virge->s3d.pattern_16; + break; + case CMD_SET_FORMAT_24: + default: + bpp = 2; + x_mul = 3; + cpu_dat_shift = 24; + pattern_data = virge->s3d.pattern_32; + break; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + pattern_data = mono_pattern; + + switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK) + { + case CMD_SET_ITA_BYTE: + count_mask = ~0x7; + break; + case CMD_SET_ITA_WORD: + count_mask = ~0xf; + break; + case CMD_SET_ITA_DWORD: + default: + count_mask = ~0x1f; + break; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + { + int x, y; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 8; x++) + { + if (virge->s3d.mono_pat_0 & (1 << (x + y*8))) + mono_pattern[y*8 + x] = virge->s3d.pat_fg_clr; + else + mono_pattern[y*8 + x] = virge->s3d.pat_bg_clr; + if (virge->s3d.mono_pat_1 & (1 << (x + y*8))) + mono_pattern[(y+4)*8 + x] = virge->s3d.pat_fg_clr; + else + mono_pattern[(y+4)*8 + x] = virge->s3d.pat_bg_clr; + } + } + } + switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK) + { + case CMD_SET_COMMAND_NOP: + break; + + case CMD_SET_COMMAND_BITBLT: + if (count == -1) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.data_left_count = 0; + +/* pclog("BitBlt start %i,%i %i,%i %i,%i %02X %x %x\n", + virge->s3d.src_x, + virge->s3d.src_y, + virge->s3d.dest_x, + virge->s3d.dest_y, + virge->s3d.w, + virge->s3d.h, + virge->s3d.rop, + virge->s3d.src_base, + virge->s3d.dest_base);*/ + + if (virge->s3d.cmd_set & CMD_SET_IDS) + return; + } + if (!virge->s3d.h) + return; + while (count) + { + uint32_t src_addr = virge->s3d.src_base + (virge->s3d.src_x * x_mul) + (virge->s3d.src_y * virge->s3d.src_str); + uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source, dest, pattern; + uint32_t out = 0; + int update = 1; + + switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) + { + case 0: + case CMD_SET_MS: + READ(src_addr, source); + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr) + update = 0; + break; + case CMD_SET_IDS: + if (virge->s3d.data_left_count) + { + /*Handle shifting for 24-bit data*/ + source = virge->s3d.data_left; + source |= ((cpu_dat << virge->s3d.data_left_count) & ~0xff000000); + cpu_dat >>= (cpu_dat_shift - virge->s3d.data_left_count); + count -= (cpu_dat_shift - virge->s3d.data_left_count); + virge->s3d.data_left_count = 0; + if (count < cpu_dat_shift) + { + virge->s3d.data_left = cpu_dat; + virge->s3d.data_left_count = count; + count = 0; + } + } + else + { + source = cpu_dat; + cpu_dat >>= cpu_dat_shift; + count -= cpu_dat_shift; + if (count < cpu_dat_shift) + { + virge->s3d.data_left = cpu_dat; + virge->s3d.data_left_count = count; + count = 0; + } + } + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr) + update = 0; + break; + case CMD_SET_IDS | CMD_SET_MS: + source = (cpu_dat & (1 << 31)) ? virge->s3d.src_fg_clr : virge->s3d.src_bg_clr; + if ((virge->s3d.cmd_set & CMD_SET_TP) && !(cpu_dat & (1 << 31))) + update = 0; + cpu_dat <<= 1; + count--; + break; + } + + CLIP(virge->s3d.dest_x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + pattern = pattern_data[(virge->s3d.dest_y & 7)*8 + (virge->s3d.dest_x & 7)]; + MIX(); + + WRITE(dest_addr, out); + } + + virge->s3d.src_x += x_inc; + virge->s3d.src_x &= 0x7ff; + virge->s3d.dest_x += x_inc; + virge->s3d.dest_x &= 0x7ff; + if (!virge->s3d.w) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.w = virge->s3d.r_width; + + virge->s3d.src_y += y_inc; + virge->s3d.dest_y += y_inc; + virge->s3d.h--; + + switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) + { + case CMD_SET_IDS: + cpu_dat >>= (count - (count & count_mask)); + count &= count_mask; + virge->s3d.data_left_count = 0; + break; + + case CMD_SET_IDS | CMD_SET_MS: + cpu_dat <<= (count - (count & count_mask)); + count &= count_mask; + break; + } + if (!virge->s3d.h) + { + return; + } + } + else + virge->s3d.w--; + } + break; + + case CMD_SET_COMMAND_RECTFILL: + /*No source, pattern = pat_fg_clr*/ + if (count == -1) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + +/* pclog("RctFll start %i,%i %i,%i %02X %08x\n", virge->s3d.dest_x, + virge->s3d.dest_y, + virge->s3d.w, + virge->s3d.h, + virge->s3d.rop, virge->s3d.dest_base);*/ + } + + while (count && virge->s3d.h) + { + uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source = 0, dest, pattern = virge->s3d.pat_fg_clr; + uint32_t out = 0; + int update = 1; + + CLIP(virge->s3d.dest_x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + + MIX(); + + WRITE(dest_addr, out); + } + + virge->s3d.src_x += x_inc; + virge->s3d.src_x &= 0x7ff; + virge->s3d.dest_x += x_inc; + virge->s3d.dest_x &= 0x7ff; + if (!virge->s3d.w) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.w = virge->s3d.r_width; + + virge->s3d.src_y += y_inc; + virge->s3d.dest_y += y_inc; + virge->s3d.h--; + if (!virge->s3d.h) + { + return; + } + } + else + virge->s3d.w--; + count--; + } + break; + + case CMD_SET_COMMAND_LINE: + if (count == -1) + { + virge->s3d.dest_x = virge->s3d.lxstart; + virge->s3d.dest_y = virge->s3d.lystart; + virge->s3d.h = virge->s3d.lycnt; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + } + while (virge->s3d.h) + { + int x; + int new_x; + int first_pixel = 1; + + x = virge->s3d.dest_x >> 20; + + if (virge->s3d.h == virge->s3d.lycnt && + ((virge->s3d.line_dir && x > virge->s3d.lxend0) || + (!virge->s3d.line_dir && x < virge->s3d.lxend0))) + x = virge->s3d.lxend0; + + if (virge->s3d.h == 1) + new_x = virge->s3d.lxend1 + (virge->s3d.line_dir ? 1 : -1); + else + new_x = (virge->s3d.dest_x + virge->s3d.ldx) >> 20; + + + if ((virge->s3d.line_dir && x > new_x) || + (!virge->s3d.line_dir && x < new_x)) + goto skip_line; + + do + { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source = 0, dest, pattern; + uint32_t out = 0; + int update = 1; + + if ((virge->s3d.h == virge->s3d.lycnt || !first_pixel) && + ((virge->s3d.line_dir && x < virge->s3d.lxend0) || + (!virge->s3d.line_dir && x > virge->s3d.lxend0))) + update = 0; + + if ((virge->s3d.h == 1 || !first_pixel) && + ((virge->s3d.line_dir && x > virge->s3d.lxend1) || + (!virge->s3d.line_dir && x < virge->s3d.lxend1))) + update = 0; + + CLIP(x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + pattern = virge->s3d.pat_fg_clr; + + MIX(); + + WRITE(dest_addr, out); + } + + if (x < new_x) + x++; + else if (x > new_x) + x--; + first_pixel = 0; + } while (x != new_x); + +skip_line: + virge->s3d.dest_x += virge->s3d.ldx; + virge->s3d.dest_y--; + virge->s3d.h--; + } + break; + + case CMD_SET_COMMAND_POLY: + /*No source*/ + if (virge->s3d.pycnt & (1 << 28)) + virge->s3d.dest_r = virge->s3d.prxstart; + if (virge->s3d.pycnt & (1 << 29)) + virge->s3d.dest_l = virge->s3d.plxstart; + virge->s3d.h = virge->s3d.pycnt & 0x7ff; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + //pclog("Start poly - l=%08x r=%08x h=%i rop=%02x\n", virge->s3d.dest_l, virge->s3d.dest_r, virge->s3d.h, virge->s3d.rop); + while (virge->s3d.h) + { + int x = virge->s3d.dest_l >> 20; + int xend = virge->s3d.dest_r >> 20; + int y = virge->s3d.pystart & 0x7ff; + int xdir = (x < xend) ? 1 : -1; + //pclog(" %03i: %i - %i %08x-%08x\n", y, x, xend, virge->s3d.dest_l, virge->s3d.dest_r); + do + { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); + uint32_t source = 0, dest, pattern; + uint32_t out = 0; + int update = 1; + + CLIP(x, y); + + if (update) + { + READ(dest_addr, dest); + pattern = pattern_data[(y & 7)*8 + (x & 7)]; + MIX(); + + WRITE(dest_addr, out); + } + + x = (x + xdir) & 0x7ff; + } + while (x != (xend + xdir)); + + virge->s3d.dest_l += virge->s3d.pldx; + virge->s3d.dest_r += virge->s3d.prdx; + virge->s3d.h--; + virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; + } + break; + + default: + fatal("s3_virge_bitblt : blit command %i %08x\n", (virge->s3d.cmd_set >> 27) & 0xf, virge->s3d.cmd_set); + } +} + +#define RGB15_TO_24(val, r, g, b) b = ((val & 0x001f) << 3) | ((val & 0x001f) >> 2); \ + g = ((val & 0x03e0) >> 2) | ((val & 0x03e0) >> 7); \ + r = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); + +#define RGB24_TO_24(val, r, g, b) b = val & 0xff; \ + g = (val & 0xff00) >> 8; \ + r = (val & 0xff0000) >> 16 + +#define RGB15(r, g, b, dest) \ + if (virge->dithering_enabled) \ + { \ + int add = dither[_y & 3][_x & 3]; \ + int _r = (r > 248) ? 248 : r+add; \ + int _g = (g > 248) ? 248 : g+add; \ + int _b = (b > 248) ? 248 : b+add; \ + dest = ((_b >> 3) & 0x1f) | (((_g >> 3) & 0x1f) << 5) | (((_r >> 3) & 0x1f) << 10); \ + } \ + else \ + dest = ((b >> 3) & 0x1f) | (((g >> 3) & 0x1f) << 5) | (((r >> 3) & 0x1f) << 10) + +#define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + +typedef struct rgba_t +{ + int r, g, b, a; +} rgba_t; + +typedef struct s3d_state_t +{ + int32_t r, g, b, a, u, v, d, w; + + int32_t base_r, base_g, base_b, base_a, base_u, base_v, base_d, base_w; + + uint32_t base_z; + + uint32_t tbu, tbv; + + uint32_t cmd_set; + int max_d; + + uint16_t *texture[10]; + + uint32_t tex_bdr_clr; + + int32_t x1, x2; + int y; + + rgba_t dest_rgba; +} s3d_state_t; + +typedef struct s3d_texture_state_t +{ + int level; + int texture_shift; + + int32_t u, v; +} s3d_texture_state_t; + +static void (*tex_read)(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out); +static void (*tex_sample)(s3d_state_t *state); +static void (*dest_pixel)(s3d_state_t *state); + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static int _x, _y; + +static void tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12); + out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7); + out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2); + out->a = (val & 0x8000) ? 0xff : 0; +} + +static void tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12); + out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7); + out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2); + out->a = (val & 0x8000) ? 0xff : 0; +} + +static void tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8); + out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4); + out->b = ((val & 0x000f) << 4) | (val & 0x000f); + out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12); +} + +static void tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8); + out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4); + out->b = ((val & 0x000f) << 4) | (val & 0x000f); + out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12); +} + +static void tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; + + out->r = (val >> 16) & 0xff; + out->g = (val >> 8) & 0xff; + out->b = val & 0xff; + out->a = (val >> 24) & 0xff; +} +static void tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = (val >> 16) & 0xff; + out->g = (val >> 8) & 0xff; + out->b = val & 0xff; + out->a = (val >> 24) & 0xff; +} + +static void tex_sample_normal(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_normal_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[0]); + du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_mipmap(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_mipmap_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[0]); + du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_normal(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_normal_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_normal_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_normal_filter_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + + +static void tex_sample_persp_mipmap(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_mipmap_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_mipmap_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define CLAMP_RGBA(r, g, b, a) \ + if ((r) & ~0xff) \ + r = ((r) < 0) ? 0 : 0xff; \ + if ((g) & ~0xff) \ + g = ((g) < 0) ? 0 : 0xff; \ + if ((b) & ~0xff) \ + b = ((b) < 0) ? 0 : 0xff; \ + if ((a) & ~0xff) \ + a = ((a) < 0) ? 0 : 0xff; + +#define CLAMP_RGB(r, g, b) do \ + { \ + if ((r) < 0) \ + r = 0; \ + if ((r) > 0xff) \ + r = 0xff; \ + if ((g) < 0) \ + g = 0; \ + if ((g) > 0xff) \ + g = 0xff; \ + if ((b) < 0) \ + b = 0; \ + if ((b) > 0xff) \ + b = 0xff; \ + } \ + while (0) + +static void dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) +{ + state->dest_rgba.r = state->r >> 7; + CLAMP(state->dest_rgba.r); + + state->dest_rgba.g = state->g >> 7; + CLAMP(state->dest_rgba.g); + + state->dest_rgba.b = state->b >> 7; + CLAMP(state->dest_rgba.b); + + state->dest_rgba.a = state->a >> 7; + CLAMP(state->dest_rgba.a); +} + +static void dest_pixel_unlit_texture_triangle(s3d_state_t *state) +{ + tex_sample(state); + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = state->a >> 7; +} + +static void dest_pixel_lit_texture_decal(s3d_state_t *state) +{ + tex_sample(state); + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = state->a >> 7; +} + +static void dest_pixel_lit_texture_reflection(s3d_state_t *state) +{ + tex_sample(state); + + state->dest_rgba.r += (state->r >> 7); + state->dest_rgba.g += (state->g >> 7); + state->dest_rgba.b += (state->b >> 7); + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a += (state->a >> 7); + + CLAMP_RGBA(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, state->dest_rgba.a); +} + +static void dest_pixel_lit_texture_modulate(s3d_state_t *state) +{ + int r = state->r >> 7, g = state->g >> 7, b = state->b >> 7, a = state->a >> 7; + + tex_sample(state); + + CLAMP_RGBA(r, g, b, a); + + state->dest_rgba.r = ((state->dest_rgba.r) * r) >> 8; + state->dest_rgba.g = ((state->dest_rgba.g) * g) >> 8; + state->dest_rgba.b = ((state->dest_rgba.b) * b) >> 8; + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = a; +} + +static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) +{ + uint8_t *vram = virge->svga.vram; + + int x_dir = s3d_tri->tlr ? 1 : -1; + + int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); + + int y_count = yc; + + int bpp = (s3d_tri->cmd_set >> 2) & 7; + + uint32_t dest_offset, z_offset; + + if (s3d_tri->cmd_set & CMD_SET_HC) + { + if (state->y < s3d_tri->clip_t) + return; + if (state->y > s3d_tri->clip_b) + { + int diff_y = state->y - s3d_tri->clip_b; + + if (diff_y > y_count) + diff_y = y_count; + + state->base_u += (s3d_tri->TdUdY * diff_y); + state->base_v += (s3d_tri->TdVdY * diff_y); + state->base_z += (s3d_tri->TdZdY * diff_y); + state->base_r += (s3d_tri->TdRdY * diff_y); + state->base_g += (s3d_tri->TdGdY * diff_y); + state->base_b += (s3d_tri->TdBdY * diff_y); + state->base_a += (s3d_tri->TdAdY * diff_y); + state->base_d += (s3d_tri->TdDdY * diff_y); + state->base_w += (s3d_tri->TdWdY * diff_y); + state->x1 += (dx1 * diff_y); + state->x2 += (dx2 * diff_y); + state->y -= diff_y; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + y_count -= diff_y; + } + if ((state->y - y_count) < s3d_tri->clip_t) + y_count = state->y - s3d_tri->clip_t; + } + + dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); + z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); + + for (; y_count > 0; y_count--) + { + int x = (state->x1 + ((1 << 20) - 1)) >> 20; + int xe = (state->x2 + ((1 << 20) - 1)) >> 20; + uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0; + if (x_dir < 0) + { + x--; + xe--; + } + + if (x != xe && (x_dir > 0 && x < xe) || (x_dir < 0 && x > xe)) + { + uint32_t dest_addr, z_addr; + int dx = (x_dir > 0) ? ((31 - ((state->x1-1) >> 15)) & 0x1f) : (((state->x1-1) >> 15) & 0x1f); + int x_offset = x_dir * (bpp + 1); + int xz_offset = x_dir << 1; + if (x_dir > 0) + dx += 1; + state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); + state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); + state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); + state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); + state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); + state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); + state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); + state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); + z += ((s3d_tri->TdZdX * dx) >> 5); + +// pclog("Draw Y=%i X=%i to XE=%i %i %08x %08x %08x %08x %08x %08x %08x %08x %i %08x\n", state->y, x, xe, dx, state->x1, state->x2, dx1, virge->s3d.TdWdX, state->u, state->v, virge->s3d.TdUdX, virge->s3d.TdUdY, dx, (virge->s3d.TdUdX * dx) >> 4); + + if (s3d_tri->cmd_set & CMD_SET_HC) + { + if (x_dir > 0) + { + if (x > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + xe = s3d_tri->clip_r; + if (x < s3d_tri->clip_l) + { + int diff_x = s3d_tri->clip_l - x; + + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); + + x = s3d_tri->clip_l; + } + } + else + { + if (x < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + xe = s3d_tri->clip_l; + if (x > s3d_tri->clip_r) + { + int diff_x = x - s3d_tri->clip_r; + + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); + + x = s3d_tri->clip_r; + } + } + } + + virge->svga.changedvram[(dest_offset & 0x3fffff) >> 12] = changeframecount; + + dest_addr = dest_offset + (x * (bpp + 1)); + z_addr = z_offset + (x << 1); + + for (; x != xe; x = (x + x_dir) & 0xfff) + { + int update = 1; + uint16_t src_z; + _x = x; _y = state->y; + + if (use_z) + { + src_z = Z_READ(z_addr); + Z_CLIP(src_z, z >> 16); + } + + if (update) + { + uint32_t dest_col; + + dest_pixel(state); + + if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) + { + uint32_t src_col; + int src_r, src_g, src_b; + + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + src_col = *(uint16_t *)&vram[dest_addr & 0x3fffff]; + RGB15_TO_24(src_col, src_r, src_g, src_b); + break; + case 2: /*24 bpp*/ + src_col = (*(uint32_t *)&vram[dest_addr & 0x3fffff]) & 0xffffff; + RGB24_TO_24(src_col, src_r, src_g, src_b); + break; + } + + state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255; + } + + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); + *(uint16_t *)&vram[dest_addr] = dest_col; + break; + case 2: /*24 bpp*/ + dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); + *(uint8_t *)&vram[dest_addr] = dest_col & 0xff; + *(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff; + *(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff; + break; + } + + if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) + Z_WRITE(z_addr, src_z); + } + + z += s3d_tri->TdZdX; + state->u += s3d_tri->TdUdX; + state->v += s3d_tri->TdVdX; + state->r += s3d_tri->TdRdX; + state->g += s3d_tri->TdGdX; + state->b += s3d_tri->TdBdX; + state->a += s3d_tri->TdAdX; + state->d += s3d_tri->TdDdX; + state->w += s3d_tri->TdWdX; + dest_addr += x_offset; + z_addr += xz_offset; + virge->pixel_count++; + } + } +tri_skip_line: + state->x1 += dx1; + state->x2 += dx2; + state->base_u += s3d_tri->TdUdY; + state->base_v += s3d_tri->TdVdY; + state->base_z += s3d_tri->TdZdY; + state->base_r += s3d_tri->TdRdY; + state->base_g += s3d_tri->TdGdY; + state->base_b += s3d_tri->TdBdY; + state->base_a += s3d_tri->TdAdY; + state->base_d += s3d_tri->TdDdY; + state->base_w += s3d_tri->TdWdY; + state->y--; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + } +} + +static int tex_size[8] = +{ + 4*2, + 2*2, + 2*2, + 1*2, + 2/1, + 2/1, + 1*2, + 1*2 +}; + +static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) +{ + s3d_state_t state; + + uint32_t tex_base; + int c; + + uint64_t start_time = timer_read(); + uint64_t end_time; + + state.tbu = s3d_tri->tbu << 11; + state.tbv = s3d_tri->tbv << 11; + + state.max_d = (s3d_tri->cmd_set >> 8) & 15; + + state.tex_bdr_clr = s3d_tri->tex_bdr_clr; + + state.cmd_set = s3d_tri->cmd_set; + + state.base_u = s3d_tri->tus; + state.base_v = s3d_tri->tvs; + state.base_z = s3d_tri->tzs; + state.base_r = (int32_t)s3d_tri->trs; + state.base_g = (int32_t)s3d_tri->tgs; + state.base_b = (int32_t)s3d_tri->tbs; + state.base_a = (int32_t)s3d_tri->tas; + state.base_d = s3d_tri->tds; + state.base_w = s3d_tri->tws; + + tex_base = s3d_tri->tex_base; + for (c = 9; c >= 0; c--) + { + state.texture[c] = (uint16_t *)&virge->svga.vram[tex_base]; + if (c <= state.max_d) + tex_base += ((1 << (c*2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; + } + + switch ((s3d_tri->cmd_set >> 27) & 0xf) + { + case 0: + dest_pixel = dest_pixel_gouraud_shaded_triangle; +// pclog("dest_pixel_gouraud_shaded_triangle\n"); + break; + case 1: + case 5: + switch ((s3d_tri->cmd_set >> 15) & 0x3) + { + case 0: + dest_pixel = dest_pixel_lit_texture_reflection; +// pclog("dest_pixel_lit_texture_reflection\n"); + break; + case 1: + dest_pixel = dest_pixel_lit_texture_modulate; +// pclog("dest_pixel_lit_texture_modulate\n"); + break; + case 2: + dest_pixel = dest_pixel_lit_texture_decal; +// pclog("dest_pixel_lit_texture_decal\n"); + break; + default: + pclog("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); + return; + } + break; + case 2: + case 6: + dest_pixel = dest_pixel_unlit_texture_triangle; +// pclog("dest_pixel_unlit_texture_triangle\n"); + break; + default: + pclog("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); + return; + } + + switch (((s3d_tri->cmd_set >> 12) & 7) | ((s3d_tri->cmd_set & (1 << 29)) ? 8 : 0)) + { + case 0: case 1: + tex_sample = tex_sample_mipmap; +// pclog("use tex_sample_mipmap\n"); + break; + case 2: case 3: + tex_sample = virge->bilinear_enabled ? tex_sample_mipmap_filter : tex_sample_mipmap; +// pclog("use tex_sample_mipmap_filter\n"); + break; + case 4: case 5: + tex_sample = tex_sample_normal; +// pclog("use tex_sample_normal\n"); + break; + case 6: case 7: + tex_sample = virge->bilinear_enabled ? tex_sample_normal_filter : tex_sample_normal; +// pclog("use tex_sample_normal_filter\n"); + break; + case (0 | 8): case (1 | 8): + if (virge->is_375) + tex_sample = tex_sample_persp_mipmap_375; + else + tex_sample = tex_sample_persp_mipmap; +// pclog("use tex_sample_persp_mipmap\n"); + break; + case (2 | 8): case (3 | 8): + if (virge->is_375) + tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter_375 : tex_sample_persp_mipmap_375; + else + tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter : tex_sample_persp_mipmap; +// pclog("use tex_sample_persp_mipmap_filter\n"); + break; + case (4 | 8): case (5 | 8): + if (virge->is_375) + tex_sample = tex_sample_persp_normal_375; + else + tex_sample = tex_sample_persp_normal; +// pclog("use tex_sample_persp_normal\n"); + break; + case (6 | 8): case (7 | 8): + if (virge->is_375) + tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter_375 : tex_sample_persp_normal_375; + else + tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter : tex_sample_persp_normal; +// pclog("use tex_sample_persp_normal_filter\n"); + break; + } + + switch ((s3d_tri->cmd_set >> 5) & 7) + { + case 0: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB8888 : tex_ARGB8888_nowrap; + break; + case 1: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB4444 : tex_ARGB4444_nowrap; +// pclog("tex_ARGB4444\n"); + break; + case 2: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; +// pclog("tex_ARGB1555 %i\n", (s3d_tri->cmd_set >> 5) & 7); + break; + default: + pclog("bad texture type %i\n", (s3d_tri->cmd_set >> 5) & 7); + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; + break; + } + +// pclog("Triangle %i %i,%i to %i,%i %08x\n", y, x1 >> 20, y, s3d_tri->txend01 >> 20, y - (s3d_tri->ty01 + s3d_tri->ty12), state.cmd_set); + + state.y = s3d_tri->tys; + state.x1 = s3d_tri->txs; + state.x2 = s3d_tri->txend01; + tri(virge, s3d_tri, &state, s3d_tri->ty01, s3d_tri->TdXdY02, s3d_tri->TdXdY01); + state.x2 = s3d_tri->txend12; + tri(virge, s3d_tri, &state, s3d_tri->ty12, s3d_tri->TdXdY02, s3d_tri->TdXdY12); + + virge->tri_count++; + + end_time = timer_read(); + + virge_time += end_time - start_time; +} + +static void render_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (1) + { + thread_wait_event(virge->wake_render_thread, -1); + thread_reset_event(virge->wake_render_thread); + virge->s3d_busy = 1; + while (!RB_EMPTY) + { + s3_virge_triangle(virge, &virge->s3d_buffer[virge->s3d_read_idx & RB_MASK]); + virge->s3d_read_idx++; + + if (RB_ENTRIES == RB_SIZE - 1) + thread_set_event(virge->not_full_event); + } + virge->s3d_busy = 0; + } +} + +static void queue_triangle(virge_t *virge) +{ + int c; +// pclog("queue_triangle: read=%i write=%i RB_ENTRIES=%i RB_FULL=%i\n", virge->s3d_read_idx, virge->s3d_write_idx, RB_ENTRIES, RB_FULL); + if (RB_FULL) + { + thread_reset_event(virge->not_full_event); + if (RB_FULL) + thread_wait_event(virge->not_full_event, -1); /*Wait for room in ringbuffer*/ + } +// pclog(" add at read=%i write=%i %i\n", virge->s3d_read_idx, virge->s3d_write_idx, virge->s3d_write_idx & RB_MASK); + virge->s3d_buffer[virge->s3d_write_idx & RB_MASK] = virge->s3d_tri; + virge->s3d_write_idx++; + if (!virge->s3d_busy) + thread_set_event(virge->wake_render_thread); /*Wake up render thread if moving from idle*/ +} + +static void s3_virge_hwcursor_draw(svga_t *svga, int displine) +{ + virge_t *virge = (virge_t *)svga->p; + int x; + uint16_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + +// pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y); + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + if (svga->crtc[0x55] & 0x10) + { + /*X11*/ + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (dat[0] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = virge->hwcursor_col[dat[1] >> 15]; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + } + else + { + /*Windows*/ + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = virge->hwcursor_col[dat[1] >> 15]; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; +// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga->hwcursor_on, dat[0], dat[1]); + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + } + svga->hwcursor_latch.addr += 4; + } +} + +#define DECODE_YCbCr() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +/*Both YUV formats are untested*/ +#define DECODE_YUV211() \ + do \ + { \ + uint8_t y1, y2, y3, y4; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + y2 = (298 * (src[2] - 16)) >> 8; \ + V = src[3] - 0x80; \ + y3 = (298 * (src[4] - 16)) >> 8; \ + y4 = (298 * (src[5] - 16)) >> 8; \ + src += 6; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + r[x_write+2] = y2 + dR; \ + CLAMP(r[x_write+2]); \ + g[x_write+2] = y2 - dG; \ + CLAMP(g[x_write+2]); \ + b[x_write+2] = y2 + dB; \ + CLAMP(b[x_write+2]); \ + \ + r[x_write+3] = y2 + dR; \ + CLAMP(r[x_write+3]); \ + g[x_write+3] = y2 - dG; \ + CLAMP(g[x_write+3]); \ + b[x_write+3] = y2 + dB; \ + CLAMP(b[x_write+3]); \ + \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_YUV422() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + V = src[2] - 0x80; \ + y2 = (298 * (src[3] - 16)) >> 8; \ + src += 4; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +#define DECODE_RGB555() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \ + b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \ + b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 3; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_XRGB8888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 4; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define OVERLAY_SAMPLE() \ + do \ + { \ + switch (virge->streams.sdif) \ + { \ + case 1: \ + DECODE_YCbCr(); \ + break; \ + case 2: \ + DECODE_YUV422(); \ + break; \ + case 3: \ + DECODE_RGB555(); \ + break; \ + case 4: \ + DECODE_YUV211(); \ + break; \ + case 5: \ + DECODE_RGB565(); \ + break; \ + case 6: \ + DECODE_RGB888(); \ + break; \ + case 7: \ + default: \ + DECODE_XRGB8888(); \ + break; \ + } \ + } while (0) + +static void s3_virge_overlay_draw(svga_t *svga, int displine) +{ + virge_t *virge = (virge_t *)svga->p; + int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1; + int h_acc = virge->streams.dda_horiz_accumulator; + int r[8], g[8], b[8]; + int r_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int g_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int b_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int x_size, x_read = 4, x_write = 4; + int x; + uint32_t *p; + uint8_t *src = &svga->vram[svga->overlay_latch.addr]; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + p = &((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add]; + + if ((offset + virge->streams.sec_w) > virge->streams.pri_w) + x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1; + else + x_size = virge->streams.sec_w + 1; + + OVERLAY_SAMPLE(); + + for (x = 0; x < x_size; x++) + { + *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); + + h_acc += virge->streams.k1_horiz_scale; + if (h_acc >= 0) + { + if ((x_read ^ (x_read + 1)) & ~3) + OVERLAY_SAMPLE(); + x_read = (x_read + 1) & 7; + + h_acc += (virge->streams.k2_horiz_scale - virge->streams.k1_horiz_scale); + } + } + + svga->overlay_latch.v_acc += virge->streams.k1_vert_scale; + if (svga->overlay_latch.v_acc >= 0) + { + svga->overlay_latch.v_acc += (virge->streams.k2_vert_scale - virge->streams.k1_vert_scale); + svga->overlay_latch.addr += virge->streams.sec_stride; + } +} + +static uint8_t s3_virge_pci_read(int func, int addr, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t ret = 0; +// pclog("S3 PCI read %08X ", addr); + switch (addr) + { + case 0x00: ret = 0x33; break; /*'S3'*/ + case 0x01: ret = 0x53; break; + + case 0x02: ret = virge->virge_id_low; break; + case 0x03: ret = virge->virge_id_high; break; + + case 0x04: ret = virge->pci_regs[0x04] & 0x27; break; + + case 0x07: ret = virge->pci_regs[0x07] & 0x36; break; + + case 0x08: ret = 0; break; /*Revision ID*/ + case 0x09: ret = 0; break; /*Programming interface*/ + + case 0x0a: ret = 0x00; break; /*Supports VGA interface*/ + case 0x0b: ret = 0x03; /*output = 3; */break; + + case 0x0d: ret = virge->pci_regs[0x0d] & 0xf8; break; + + case 0x10: ret = 0x00; break;/*Linear frame buffer address*/ + case 0x11: ret = 0x00; break; + case 0x12: ret = 0x00; break; + case 0x13: ret = svga->crtc[0x59] & 0xfc; break; + + case 0x30: ret = virge->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ + case 0x31: ret = 0x00; break; + case 0x32: ret = virge->pci_regs[0x32]; break; + case 0x33: ret = virge->pci_regs[0x33]; break; + + case 0x3c: ret = virge->pci_regs[0x3c]; break; + + case 0x3d: ret = 0x01; break; /*INTA*/ + + case 0x3e: ret = 0x04; break; + case 0x3f: ret = 0xff; break; + + } +// pclog("%02X\n", ret); + return ret; +} + +static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; +// pclog("S3 PCI write %08X %02X %04X:%08X\n", addr, val, CS, pc); + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x3d: case 0x3e: case 0x3f: + return; + + case PCI_REG_COMMAND: + if (romset == ROM_KN97) return; + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + } + else + io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + virge->pci_regs[PCI_REG_COMMAND] = val & 0x27; + s3_virge_updatemapping(virge); + return; + case 0x07: + virge->pci_regs[0x07] = val & 0x3e; + return; + case 0x0d: + virge->pci_regs[0x0d] = val & 0xf8; + return; + + case 0x13: + svga->crtc[0x59] = val & 0xfc; + s3_virge_updatemapping(virge); + return; + + case 0x30: case 0x32: case 0x33: + virge->pci_regs[addr] = val; + if (virge->pci_regs[0x30] & 0x01) + { + uint32_t addr = (virge->pci_regs[0x32] << 16) | (virge->pci_regs[0x33] << 24); +// pclog("Virge bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&virge->bios_rom.mapping, addr, 0x8000); + mem_mapping_enable(&virge->bios_rom.mapping); + } + else + { +// pclog("Virge bios_rom disabled\n"); + mem_mapping_disable(&virge->bios_rom.mapping); + } + return; + case 0x3c: + virge->pci_regs[0x3c] = val; + return; + } +} + +static void *s3_virge_init() +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + + rom_init(&virge->bios_rom, "roms/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x56; + virge->virge_id_low = 0x31; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + + virge->svga.crtc[0x37] = 1;// | (7 << 5); + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->is_375 = 0; + + pci_add(s3_virge_pci_read, s3_virge_pci_write, virge); + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void *s3_virge_375_init() +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + + rom_init(&virge->bios_rom, "roms/86c375_1.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x8a; + virge->virge_id_low = 0x01; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } +// virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4); + virge->svga.crtc[0x37] = 1;// | (7 << 5); + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->svga.crtc[0x6c] = 0x01; + + virge->is_375 = 1; + + pci_add(s3_virge_pci_read, s3_virge_pci_write, virge); + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void s3_virge_close(void *p) +{ + virge_t *virge = (virge_t *)p; +#ifndef RELEASE_BUILD + FILE *f = fopen("vram.dmp", "wb"); + fwrite(virge->svga.vram, 4 << 20, 1, f); + fclose(f); +#endif + + thread_kill(virge->render_thread); + thread_destroy_event(virge->not_full_event); + thread_destroy_event(virge->wake_main_thread); + thread_destroy_event(virge->wake_render_thread); + + svga_close(&virge->svga); + + free(virge); +} + +static int s3_virge_available() +{ + return rom_present("roms/s3virge.bin"); +} + +static int s3_virge_375_available() +{ + return rom_present("roms/86c375_1.bin"); +} + +static void s3_virge_speed_changed(void *p) +{ + virge_t *virge = (virge_t *)p; + + svga_recalctimings(&virge->svga); +} + +static void s3_virge_force_redraw(void *p) +{ + virge_t *virge = (virge_t *)p; + + virge->svga.fullchange = changeframecount; +} + +static void s3_virge_add_status_info(char *s, int max_len, void *p) +{ + virge_t *virge = (virge_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + status_time = new_time; + + if (!status_diff) + status_diff = 1; + + svga_add_status_info(s, max_len, &virge->svga); + sprintf(temps, "%f Mpixels/sec\n%f ktris/sec\n%f%% CPU\n%f%% CPU (real)\n%d writes %i reads\n\n", (double)virge->pixel_count/1000000.0, (double)virge->tri_count/1000.0, ((double)virge_time * 100.0) / timer_freq, ((double)virge_time * 100.0) / status_diff, reg_writes, reg_reads); + strncat(s, temps, max_len); + + virge->pixel_count = virge->tri_count = 0; + virge_time = 0; + reg_reads = 0; + reg_writes = 0; +} + +static device_config_t s3_virge_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = -1 + } +}; + +device_t s3_virge_device = +{ + "Diamond Stealth 3D 2000 (S3 ViRGE)", + 0, + s3_virge_init, + s3_virge_close, + s3_virge_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_add_status_info, + s3_virge_config +}; + +device_t s3_virge_375_device = +{ + "S3 ViRGE/DX", + 0, + s3_virge_375_init, + s3_virge_close, + s3_virge_375_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_add_status_info, + s3_virge_config +}; diff --git a/src/vid_s3_virge.h b/src/vid_s3_virge.h new file mode 100644 index 000000000..dce1a2495 --- /dev/null +++ b/src/vid_s3_virge.h @@ -0,0 +1,2 @@ +extern device_t s3_virge_device; +extern device_t s3_virge_375_device; diff --git a/src/vid_sdac_ramdac.c b/src/vid_sdac_ramdac.c new file mode 100644 index 000000000..2094f356d --- /dev/null +++ b/src/vid_sdac_ramdac.c @@ -0,0 +1,169 @@ +/*87C716 'SDAC' true colour RAMDAC emulation*/ +/*Misidentifies as AT&T 21C504*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sdac_ramdac.h" + +void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga) +{ +// /*if (CS!=0xC000) */pclog("OUT RAMDAC %04X %02X %i %04X:%04X %i\n",addr,val,sdac_ramdac.magic_count,CS,pc, sdac_ramdac.rs2); + switch (addr) + { + case 0x3C6: + if (val == 0xff) + { + ramdac->rs2 = 0; + ramdac->magic_count = 0; + break; + } + if (ramdac->magic_count < 4) break; + if (ramdac->magic_count == 4) + { + ramdac->command = val; +// pclog("RAMDAC command reg now %02X\n", val); + // 0, 1 = 15 bpp + if (gfxcard == GFX_ET4000W32C) + { + if (ramdac->command & 8) + { + switch (ramdac->regs[3]) + { + case 0: case 5: case 7: svga->bpp = 8; break; + case 1: case 2: case 8: svga->bpp = 15; break; + case 3: case 6: svga->bpp = 16; break; + case 4: case 9: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + else + { + switch (ramdac->command >> 5) + { + case 0: svga->bpp = 8; break; + case 5: svga->bpp = 15; break; + case 6: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + } + else + { + switch (val >> 4) + { + case 0x2: case 0x3: case 0xa: svga->bpp = 15; break; + case 0x4: case 0xe: svga->bpp = 24; break; + case 0x5: case 0x6: case 0xc: svga->bpp = 16; break; + case 0x7: svga->bpp = 32; break; + + case 0: case 1: default: svga->bpp = 8; break; + } + } + pclog("SDAC: Value %02X/%02X set to %i bpp\n", val >> 4, val, svga->bpp); + } + //ramdac->magic_count = 0; + break; + + case 0x3C7: + ramdac->magic_count = 0; + if (ramdac->rs2) + ramdac->rindex = val; + break; + case 0x3C8: + ramdac->magic_count = 0; + if (ramdac->rs2) + ramdac->windex = val; + break; + case 0x3C9: + ramdac->magic_count = 0; + if (ramdac->rs2) + { + if (!ramdac->reg_ff) ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0xff00) | val; + else ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0x00ff) | (val << 8); + ramdac->reg_ff = !ramdac->reg_ff; +// pclog("RAMDAC reg %02X now %04X\n", ramdac->windex, ramdac->regs[ramdac->windex]); + if (!ramdac->reg_ff) ramdac->windex++; + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; +// /*if (CS!=0xC000) */pclog("IN RAMDAC %04X %04X:%04X %i\n",addr,CS,pc, ramdac->rs2); + switch (addr) + { + case 0x3C6: + ramdac->reg_ff = 0; + if (ramdac->magic_count < 5) + ramdac->magic_count++; + if (ramdac->magic_count == 4) + { + temp = 0x70; /*SDAC ID*/ + ramdac->rs2 = 1; + } + if (ramdac->magic_count == 5) + { + temp = ramdac->command; + ramdac->magic_count = 0; + } + return temp; + case 0x3C7: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) return ramdac->rindex; + break; + case 0x3C8: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) return ramdac->windex; + break; + case 0x3C9: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) + { + if (!ramdac->reg_ff) temp = ramdac->regs[ramdac->rindex] & 0xff; + else temp = ramdac->regs[ramdac->rindex] >> 8; + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + { + ramdac->rindex++; + ramdac->magic_count = 0; + } + return temp; + } + break; + } + return svga_in(addr, svga); +} + +float sdac_getclock(int clock, void *p) +{ + sdac_ramdac_t *ramdac = (sdac_ramdac_t *)p; + float t; + int m, n1, n2; +// pclog("SDAC_Getclock %i %04X\n", clock, ramdac->regs[clock]); + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + m = (ramdac->regs[clock] & 0x7f) + 2; + n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; + n2 = ((ramdac->regs[clock] >> 13) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); +// pclog("SDAC clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); + return t; +} diff --git a/src/vid_sdac_ramdac.h b/src/vid_sdac_ramdac.h new file mode 100644 index 000000000..3aaf78730 --- /dev/null +++ b/src/vid_sdac_ramdac.h @@ -0,0 +1,14 @@ +typedef struct sdac_ramdac_t +{ + int magic_count; + uint8_t command; + int windex, rindex; + uint16_t regs[256]; + int reg_ff; + int rs2; +} sdac_ramdac_t; + +void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga); +uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga); + +float sdac_getclock(int clock, void *p); diff --git a/src/vid_stg_ramdac.c b/src/vid_stg_ramdac.c new file mode 100644 index 000000000..6e361d670 --- /dev/null +++ b/src/vid_stg_ramdac.c @@ -0,0 +1,137 @@ +/*STG1702 true colour RAMDAC emulation*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_stg_ramdac.h" + +static int stg_state_read[2][8] = {{1,2,3,4,0,0,0,0}, {1,2,3,4,5,6,7,7}}; +static int stg_state_write[8] = {0,0,0,0,0,6,7,7}; + +void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga) +{ + int didwrite; + //if (CS!=0xC000) pclog("OUT RAMDAC %04X %02X %i %04X:%04X\n",addr,val,stg_ramdac.magic_count,CS,pc); + switch (addr) + { + case 0x3c6: + switch (ramdac->magic_count) + { + case 0: case 1: case 2: case 3: + break; + case 4: + ramdac->command = val; + /*pclog("Write RAMDAC command %02X\n",val);*/ + break; + case 5: + ramdac->index = (ramdac->index & 0xff00) | val; + break; + case 6: + ramdac->index = (ramdac->index & 0xff) | (val << 8); + break; + case 7: +#ifndef RELEASE_BUILD + pclog("Write RAMDAC reg %02X %02X\n", ramdac->index, val); +#endif + if (ramdac->index < 0x100) + ramdac->regs[ramdac->index] = val; + ramdac->index++; + break; + } + didwrite = (ramdac->magic_count >= 4); + ramdac->magic_count = stg_state_write[ramdac->magic_count & 7]; + if (ramdac->command & 8) + { + switch (ramdac->regs[3]) + { + case 0: case 5: case 7: svga->bpp = 8; break; + case 1: case 2: case 8: svga->bpp = 15; break; + case 3: case 6: svga->bpp = 16; break; + case 4: case 9: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + else + { + switch (ramdac->command >> 5) + { + case 0: svga->bpp = 8; break; + case 5: svga->bpp = 15; break; + case 6: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + if (didwrite) return; + break; + case 0x3c7: case 0x3c8: case 0x3c9: + ramdac->magic_count=0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; + //if (CS!=0xC000) pclog("IN RAMDAC %04X %04X:%04X\n",addr,CS,pc); + switch (addr) + { + case 0x3c6: + switch (ramdac->magic_count) + { + case 0: case 1: case 2: case 3: + temp = 0xff; + break; + case 4: + temp = ramdac->command; + break; + case 5: + temp = ramdac->index & 0xff; + break; + case 6: + temp = ramdac->index >> 8; + break; + case 7: +// pclog("Read RAMDAC index %04X\n",stg_ramdac.index); + switch (ramdac->index) + { + case 0: + temp = 0x44; + break; + case 1: + temp = 0x02; + break; + default: + if (ramdac->index < 0x100) temp = ramdac->regs[ramdac->index]; + else temp = 0xff; + break; + } + ramdac->index++; + break; + } + ramdac->magic_count = stg_state_read[(ramdac->command & 0x10) ? 1 : 0][ramdac->magic_count & 7]; + return temp; + case 0x3c8: case 0x3c9: + ramdac->magic_count=0; + break; + } + return svga_in(addr, svga); +} + +float stg_getclock(int clock, void *p) +{ + stg_ramdac_t *ramdac = (stg_ramdac_t *)p; + float t; + int m, n1, n2; +// pclog("STG_Getclock %i %04X\n", clock, ramdac->regs[clock]); + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + m = (ramdac->regs[clock] & 0x7f) + 2; + n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; + n2 = ((ramdac->regs[clock] >> 13) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); +// pclog("STG clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); + return t; +} diff --git a/src/vid_stg_ramdac.h b/src/vid_stg_ramdac.h new file mode 100644 index 000000000..2402e46cc --- /dev/null +++ b/src/vid_stg_ramdac.h @@ -0,0 +1,11 @@ +typedef struct stg_ramdac_t +{ + int magic_count; + uint8_t command; + int index; + uint8_t regs[256]; +} stg_ramdac_t; + +void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga); +uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga); +float stg_getclock(int clock, void *p); diff --git a/src/vid_svga.c b/src/vid_svga.c new file mode 100644 index 000000000..b276d44bc --- /dev/null +++ b/src/vid_svga.c @@ -0,0 +1,1634 @@ +/*Generic SVGA handling*/ +/*This is intended to be used by another SVGA driver, and not as a card in it's own right*/ +#include +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "io.h" +#include "timer.h" + +#define svga_output 0 + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); + +extern uint8_t edatlookup[4][4]; + +uint8_t svga_rotate[8][256]; + +static uint8_t mask_gdc[9] = {0x0F, 0x0F, 0x0F, 0x1F, 0x03, 0x7B, 0x0F, 0x0F, 0xFF}; +uint8_t mask_crtc[0x19] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0xEF, 0xFF}; +static uint8_t mask_seq[5] = {0x03, 0x3D, 0x0F, 0x3F, 0x0E}; + +/*Primary SVGA device. As multiple video cards are not yet supported this is the + only SVGA device.*/ +static svga_t *svga_pri; + +static int old_overscan_color = 0; + +static int sense_switches = 0xE; + +svga_t *svga_get_pri() +{ + return svga_pri; +} +void svga_set_override(svga_t *svga, int val) +{ + if (svga->override && !val) + svga->fullchange = changeframecount; + svga->override = val; +} + +void svga_out(uint16_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + int c; + uint8_t o; +// printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x3C0: + if (!svga->attrff) + { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) + { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } + else + { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) + { + for (c = 0; c < 16; c++) + { + /* Proper handling of this, per spec. */ + if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 3) << 4); + else svga->egapal[c] = (svga->attrregs[c] & 0x3f); + + // if (svga->attrregs[0x10] & 0x40) svga->egapal[c] |= ((svga->attrregs[0x14] & 0x0c) << 4); + /* It seems these should always be enabled. */ + svga->egapal[c] |= ((svga->attrregs[0x14] & 0x0c) << 4); + } + } + /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ + if ((svga->attraddr == 0x10) || (svga->attraddr == 0x11)) + { + if (o != val) svga_recalctimings(svga); + } + if (svga->attraddr == 0x12) + { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + break; + case 0x3C2: + svga->miscout = val; + svga->enablevram = (val & 2) ? 1 : 0; + svga->oddeven_page = (val & 0x20) ? 0 : 1; + svga->vidclock = val & 4;// printf("3C2 write %02X\n",val); + if (val & 1) + { +// pclog("Remove mono handler\n"); + io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + } + else + { +// pclog("Set mono handler\n"); + io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + } + svga_recalctimings(svga); + break; + case 0x3C4: + svga->seqaddr = val; + break; + case 0x3C5: + if (svga->seqaddr > 0xf) return; + o = svga->seqregs[svga->seqaddr & 0xf]; + /* Sanitize value for the first 5 sequencer registers. */ + if ((svga->seqaddr & 0xf) <= 4) + val &= mask_seq[svga->seqaddr & 0xf]; + svga->seqregs[svga->seqaddr & 0xf] = val; + if (o != val && (svga->seqaddr & 0xf) == 1) + svga_recalctimings(svga); + switch (svga->seqaddr & 0xf) + { + case 1: + if (svga->scrblank && !(val & 0x20)) + svga->fullchange = 3; + svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); + svga_recalctimings(svga); + break; + case 2: + svga->writemask = val & 0xf; + break; + case 3: + svga->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + svga->charseta = ((val & 3) * 0x10000) + 2; + if (val & 0x10) + svga->charseta += 0x8000; + if (val & 0x20) + svga->charsetb += 0x8000; + break; + case 4: + svga->chain2_write = !(val & 4); + svga->chain4 = val & 8; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4; + svga->extvram = (val & 2) ? 1 : 0; + break; + } + break; + case 0x3c6: + svga->dac_mask = val; + break; + case 0x3C7: + svga->dac_read = val; + svga->dac_pos = 0; + break; + case 0x3C8: + svga->dac_write = val; + svga->dac_pos = 0; + break; + case 0x3C9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) + { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); + else + svga->pallook[svga->dac_write] = makecol32((svga->vgapal[svga->dac_write].r & 0x3f) * 4, (svga->vgapal[svga->dac_write].g & 0x3f) * 4, (svga->vgapal[svga->dac_write].b & 0x3f) * 4); + svga->dac_pos = 0; + svga->dac_write = (svga->dac_write + 1) & 255; + break; + } + break; + case 0x3CE: + svga->gdcaddr = val; + break; + case 0x3CF: + /* Sanitize the first 9 GDC registers. */ + if ((svga->gdcaddr & 15) <= 8) + val &= mask_gdc[svga->gdcaddr & 15]; + o = svga->gdcreg[svga->gdcaddr & 15]; + switch (svga->gdcaddr & 15) + { + case 2: svga->colourcompare=val; break; + case 4: svga->readplane=val&3; break; + case 5: + svga->writemode = val & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + break; + case 6: +// pclog("svga_out recalcmapping %p\n", svga); + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) + { +// pclog("Write mapping %02X\n", val); + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0x1ffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + break; + case 7: svga->colournocare=val; break; + } + svga->gdcreg[svga->gdcaddr & 15] = val; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4; + if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) + svga_recalctimings(svga); + break; + } +} + +uint8_t svga_in(uint16_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t temp; +// if (addr!=0x3da) pclog("Read port %04X\n",addr); + switch (addr) + { + case 0x3C0: + return svga->attraddr | svga->attr_palette_enable; + case 0x3C1: + return svga->attrregs[svga->attraddr]; + case 0x3c2: +#if 0 + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; +#endif + temp = sense_switches & (1 << ((svga->miscout >> 2) & 3)); + return temp ? 0 : 0x10; + case 0x3C4: + return svga->seqaddr; + case 0x3C5: + return svga->seqregs[svga->seqaddr & 0xF]; + case 0x3c6: return svga->dac_mask; + case 0x3c7: return svga->dac_status; + case 0x3c8: return svga->dac_write; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) + { + case 0: + svga->dac_pos++; + return svga->vgapal[svga->dac_read].r; + case 1: + svga->dac_pos++; + return svga->vgapal[svga->dac_read].g; + case 2: + svga->dac_pos=0; + svga->dac_read = (svga->dac_read + 1) & 255; + return svga->vgapal[(svga->dac_read - 1) & 255].b; + } + break; + case 0x3CC: + return svga->miscout; + case 0x3CE: + return svga->gdcaddr; + case 0x3CF: + /* The spec says GDC addresses 0xF8 to 0xFB return the latch. */ + if (svga->gdcaddr == 0xF8) return svga->la; + if (svga->gdcaddr == 0xF9) return svga->lb; + if (svga->gdcaddr == 0xFA) return svga->lc; + if (svga->gdcaddr == 0xFB) return svga->ld; + return svga->gdcreg[svga->gdcaddr & 0xf]; + case 0x3DA: + svga->attrff = 0; + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x30; + else + svga->cgastat ^= 0x30; + return svga->cgastat; + } +// printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc); + return 0xFF; +} + +void svga_set_ramdac_type(svga_t *svga, int type) +{ + int c; + + if (svga->ramdac_type != type) + { + svga->ramdac_type = type; + + for (c = 0; c < 256; c++) + { + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b); + else + svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, (svga->vgapal[c].g & 0x3f) * 4, (svga->vgapal[c].b & 0x3f) * 4); + } + } +} + +void svga_recalctimings(svga_t *svga) +{ + double crtcconst; + double _dispontime, _dispofftime, disptime; + int hdisp_old; + + svga->vtotal = svga->crtc[6]; + svga->dispend = svga->crtc[0x12]; + svga->vsyncstart = svga->crtc[0x10]; + svga->split = svga->crtc[0x18]; + svga->vblankstart = svga->crtc[0x15]; + + if (svga->crtc[7] & 1) svga->vtotal |= 0x100; + if (svga->crtc[7] & 32) svga->vtotal |= 0x200; + svga->vtotal += 2; + + if (svga->crtc[7] & 2) svga->dispend |= 0x100; + if (svga->crtc[7] & 64) svga->dispend |= 0x200; + svga->dispend++; + + if (svga->crtc[7] & 4) svga->vsyncstart |= 0x100; + if (svga->crtc[7] & 128) svga->vsyncstart |= 0x200; + svga->vsyncstart++; + + if (svga->crtc[7] & 0x10) svga->split|=0x100; + if (svga->crtc[9] & 0x40) svga->split|=0x200; + svga->split++; + + if (svga->crtc[7] & 0x08) svga->vblankstart |= 0x100; + if (svga->crtc[9] & 0x20) svga->vblankstart |= 0x200; + svga->vblankstart++; + + svga->hdisp = svga->crtc[1]; + svga->hdisp++; + + svga->htotal = svga->crtc[0]; + svga->htotal += 6; /*+6 is required for Tyrian*/ + + svga->rowoffset = svga->crtc[0x13]; + + svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; + + svga->lowres = svga->attrregs[0x10] & 0x40; + + svga->interlace = 0; + + svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + + svga->hdisp_time = svga->hdisp; + svga->render = svga_render_blank; + if (!svga->scrblank && svga->attr_palette_enable) + { + if (!(svga->gdcreg[6] & 1)) /*Text mode*/ + { + if (svga->seqregs[1] & 8) /*40 column*/ + { + svga->render = svga_render_text_40; + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + } + else + { + svga->render = svga_render_text_80; + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + } + svga->hdisp_old = svga->hdisp; + } + else + { + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->hdisp_old = svga->hdisp; + + switch (svga->gdcreg[5] & 0x60) + { + case 0x00: /*16 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: /*256+ colours*/ + switch (svga->bpp) + { + case 8: + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 24: + if (svga->lowres) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; + } + break; + } + } + } + +// pclog("svga_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", svga_render, svga_render_text_40, svga_render_text_80, svga_render_8bpp_lowres, svga_render_8bpp_highres, svga_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); + + svga->linedbl = svga->crtc[9] & 0x80; + svga->rowcount = svga->crtc[9] & 31; + if (svga->recalctimings_ex) + svga->recalctimings_ex(svga); + + if (svga->vblankstart < svga->dispend) + svga->dispend = svga->vblankstart; + + crtcconst = (svga->seqregs[1] & 1) ? (svga->clock * 8.0) : (svga->clock * 9.0); + + disptime = svga->htotal; + _dispontime = svga->hdisp_time; + +// printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8); + if (svga->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +/* printf("SVGA horiz total %i display end %i vidclock %f\n",svga->crtc[0],svga->crtc[1],svga->clock); + printf("SVGA vert total %i display end %i max row %i vsync %i\n",svga->vtotal,svga->dispend,(svga->crtc[9]&31)+1,svga->vsyncstart); + printf("total %f on %i cycles off %i cycles frame %i sec %i %02X\n",disptime*crtcconst,svga->dispontime,svga->dispofftime,(svga->dispontime+svga->dispofftime)*svga->vtotal,(svga->dispontime+svga->dispofftime)*svga->vtotal*70,svga->seqregs[1]); + + pclog("svga->render %08X\n", svga->render);*/ +} + +extern int cyc_total; +void svga_poll(void *p) +{ + svga_t *svga = (svga_t *)p; + int x; + + if (!svga->linepos) + { +// if (!(vc & 15)) pclog("VC %i %i\n", vc, GetTickCount()); + if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) + { + svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; + svga->hwcursor_oddeven = 0; + } + + if (svga->displine == svga->hwcursor_latch.y+1 && svga->hwcursor_latch.ena && svga->interlace) + { + svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; + svga->hwcursor_oddeven = 1; + } + + if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) + { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 0; + } + if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) + { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 1; + } + + svga->vidtime += svga->dispofftime; +// if (output) printf("Display off %f\n",vidtime); + svga->cgastat |= 1; + svga->linepos = 1; + + if (svga->dispon) + { + svga->hdisp_on=1; + + svga->ma &= svga->vrammask; + if (svga->firstline == 2000) + svga->firstline = svga->displine; + + if (svga->hwcursor_on || svga->overlay_on) + svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = 2; + + if (!svga->override) + svga->render(svga); + + if (svga->overlay_on) + { + if (!svga->override) + svga->overlay_draw(svga, svga->displine); + svga->overlay_on--; + if (svga->overlay_on && svga->interlace) + svga->overlay_on--; + } + + if (svga->hwcursor_on) + { + if (!svga->override) + svga->hwcursor_draw(svga, svga->displine); + svga->hwcursor_on--; + if (svga->hwcursor_on && svga->interlace) + svga->hwcursor_on--; + } + + if (svga->lastline < svga->displine) + svga->lastline = svga->displine; + } + +// pclog("%03i %06X %06X\n",displine,ma,vrammask); + svga->displine++; + if (svga->interlace) + svga->displine++; + if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) + { +// printf("Vsync off at line %i\n",displine); + svga->cgastat &= ~8; + } + svga->vslines++; + if (svga->displine > 1500) + svga->displine = 0; +// pclog("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], +// displine, vc, ma); + } + else + { +// pclog("VC %i ma %05X\n", svga->vc, svga->ma); + svga->vidtime += svga->dispontime; + +// if (output) printf("Display on %f\n",vidtime); + if (svga->dispon) + svga->cgastat &= ~1; + svga->hdisp_on = 0; + + svga->linepos = 0; + if (svga->sc == (svga->crtc[11] & 31)) + svga->con = 0; + if (svga->dispon) + { + if (svga->linedbl && !svga->linecountff) + { + svga->linecountff = 1; + svga->ma = svga->maback; + } + else if (svga->sc == svga->rowcount) + { + svga->linecountff = 0; + svga->sc = 0; + + svga->maback += (svga->rowoffset << 3); + if (svga->interlace) + svga->maback += (svga->rowoffset << 3); + svga->maback &= svga->vrammask; + svga->ma = svga->maback; + } + else + { + svga->linecountff = 0; + svga->sc++; + svga->sc &= 31; + svga->ma = svga->maback; + } + } + svga->vc++; + svga->vc &= 2047; + + if (svga->vc == svga->split) + { +// pclog("VC split\n"); + svga->ma = svga->maback = 0; + if (svga->attrregs[0x10] & 0x20) + svga->scrollcache = 0; + } + if (svga->vc == svga->dispend) + { +// pclog("VC dispend\n"); + svga->dispon=0; + if (svga->crtc[10] & 0x20) svga->cursoron = 0; + else svga->cursoron = svga->blink & 16; + if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) + svga->fullchange = 2; + svga->blink++; + + for (x = 0; x < (svga->vram_limit >> 12); x++) + { + if (svga->changedvram[x]) + svga->changedvram[x]--; + } +// memset(changedvram,0,2048); + if (svga->fullchange) + svga->fullchange--; + } + if (svga->vc == svga->vsyncstart) + { + int wx, wy; +// pclog("VC vsync %i %i\n", svga->firstline_draw, svga->lastline_draw); + svga->dispon=0; + svga->cgastat |= 8; + x = svga->hdisp; + + if (svga->interlace && !svga->oddeven) svga->lastline++; + if (svga->interlace && svga->oddeven) svga->firstline--; + + wx = x; + wy = svga->lastline - svga->firstline; + + if (!svga->override) + svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); + + readflash = 0; + + svga->firstline = 2000; + svga->lastline = 0; + + svga->firstline_draw = 2000; + svga->lastline_draw = 0; + + svga->oddeven ^= 1; + + changeframecount = svga->interlace ? 3 : 2; + svga->vslines = 0; + + if (svga->interlace && svga->oddeven) svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); + else svga->ma = svga->maback = svga->ma_latch; + svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf]; + + svga->ma <<= 2; + svga->maback <<= 2; + svga->ca <<= 2; + + svga->video_res_x = wx; + svga->video_res_y = wy + 1; +// pclog("%i %i %i\n", svga->video_res_x, svga->video_res_y, svga->lowres); + if (!(svga->gdcreg[6] & 1)) /*Text mode*/ + { + svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + svga->video_bpp = 0; + } + else + { + if (svga->crtc[9] & 0x80) + svga->video_res_y /= 2; + if (!(svga->crtc[0x17] & 1)) + svga->video_res_y *= 2; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + if (svga->lowres) + svga->video_res_x /= 2; + + switch (svga->gdcreg[5] & 0x60) + { + case 0x00: svga->video_bpp = 4; break; + case 0x20: svga->video_bpp = 2; break; + case 0x40: case 0x60: svga->video_bpp = svga->bpp; break; + } + } +// if (svga_interlace && oddeven) ma=maback=ma+(svga_rowoffset<<2); + +// pclog("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,svga_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], svga_interlace, oddeven); + } + if (svga->vc == svga->vtotal) + { +// pclog("VC vtotal\n"); + + +// printf("Frame over at line %i %i %i %i\n",displine,vc,svga_vsyncstart,svga_dispend); + svga->vc = 0; + svga->sc = 0; + svga->dispon = 1; + svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; + svga->scrollcache = svga->attrregs[0x13] & 7; + svga->linecountff = 0; + + svga->hwcursor_on = 0; + svga->hwcursor_latch = svga->hwcursor; + + svga->overlay_on = 0; + svga->overlay_latch = svga->overlay; +// pclog("Latch HWcursor addr %08X\n", svga_hwcursor_latch.addr); + +// pclog("ADDR %08X\n",hwcursor_addr); + } + if (svga->sc == (svga->crtc[10] & 31)) + svga->con = 1; + } +// printf("2 %i\n",svga_vsyncstart); +//pclog("svga_poll %i %i %i %i %i %i %i\n", ins, svga->dispofftime, svga->dispontime, svga->vidtime, cyc_total, svga->linepos, svga->vc); +} + +int svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)) +{ + int c, d, e; + + svga->p = p; + + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + svga_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + svga->readmode = 0; + + svga->attrregs[0x11] = 0; + old_overscan_color = 0; + + overscan_x = 16; + overscan_y = 32; + + svga->crtc[0] = 63; + svga->crtc[6] = 255; + svga->dispontime = 1000 * (1 << TIMER_SHIFT); + svga->dispofftime = 1000 * (1 << TIMER_SHIFT); + svga->bpp = 8; + svga->vram = malloc(memsize); + svga->vram_limit = memsize; + svga->vrammask = memsize - 1; + svga->changedvram = malloc(/*(memsize >> 12) << 1*/0x800000 >> 12); + svga->recalctimings_ex = recalctimings_ex; + svga->video_in = video_in; + svga->video_out = video_out; + svga->hwcursor_draw = hwcursor_draw; + svga->overlay_draw = overlay_draw; +// _svga_recalctimings(svga); + + mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, 0, svga); + + timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); + vramp = svga->vram; + + svga_pri = svga; + + svga->ramdac_type = RAMDAC_6BIT; + + return 0; +} + +void svga_close(svga_t *svga) +{ + free(svga->changedvram); + free(svga->vram); + + svga_pri = NULL; +} + +#define egacycles 1 +#define egacycles2 1 +void svga_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t vala, valb, valc, vald, wm = svga->writemask; + int writemask2 = svga->writemask; + uint32_t raddr = addr; + int plane, mask; + + if (!svga->enablevram) return; + + egawrites++; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + if (svga_output) pclog("Writeega %06X ",addr); + addr &= svga->banked_mask; + addr += svga->write_bank; + + if (!(svga->gdcreg[6] & 1)) svga->fullchange=2; + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + if (svga->chain4 || svga->fb_only) + { + writemask2=1<<(addr&3); + addr&=~3; + } + else if (svga->chain2_write) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + mask = (1 << plane); + if (svga->seqregs[2] & mask) + { + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) return; + if ((raddr <= 0xA0000) || (raddr >= 0xBFFFF)) return; + svga->vram[addr] = val; + + svga->changedvram[addr >> 12] = changeframecount; + } + return; + } + else + { + addr<<=2; + } + addr &= 0x7fffff; + + if ((!svga->extvram) && (addr >= 0x10000)) return; + + if (addr >= svga->vram_limit) + return; + + if (svga_output) pclog("%08X (%i, %i) %02X %i %i %i %02X\n", addr, addr & 1023, addr >> 10, val, writemask2, svga->writemode, svga->chain4, svga->gdcreg[8]); + svga->changedvram[addr >> 12] = changeframecount; + + switch (svga->writemode) + { + case 1: + if (writemask2 & 1) svga->vram[addr] = svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; + break; + case 0: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = val; + if (writemask2 & 2) svga->vram[addr | 0x1] = val; + if (writemask2 & 4) svga->vram[addr | 0x2] = val; + if (writemask2 & 8) svga->vram[addr | 0x3] = val; + } + else + { + if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + } + break; + case 3: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= val; + + vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + svga->gdcreg[8] = wm; + break; + } +} + +uint8_t svga_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t temp, temp2, temp3, temp4; + uint32_t latch_addr; + int readplane = svga->readplane; + int plane; + + if (!svga->enablevram) return 0xff; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egareads++; +// pclog("Readega %06X ",addr); + addr &= svga->banked_mask; + addr += svga->read_bank; + + latch_addr = (addr << 2) & 0x7fffff; + +// pclog("%05X %i %04X:%04X %02X %02X %i\n",addr,svga->chain4,CS,pc, vram[addr & 0x7fffff], vram[(addr << 2) & 0x7fffff], svga->readmode); +// pclog("%i\n", svga->readmode); + if (svga->chain4 || svga->fb_only) + { + addr &= 0x7fffff; + if (addr >= svga->vram_limit) + return 0xff; + return svga->vram[addr]; + } + else if (svga->chain2_read) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + latch_addr = (addr << 2) & 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xff; + if (addr >= svga->vram_limit) return 0xff; + return svga->vram[addr]; + } + else + addr<<=2; + + addr &= 0x7fffff; + + if ((!svga->extvram) && (addr >= 0x10000)) return 0xff; + + if (addr >= svga->vram_limit) + return 0xff; + + if (latch_addr < svga->vram_limit) + { + svga->la = svga->vram[latch_addr]; + svga->lb = svga->vram[latch_addr | 0x1]; + svga->lc = svga->vram[latch_addr | 0x2]; + svga->ld = svga->vram[latch_addr | 0x3]; + } + else + svga->la = svga->lb = svga->lc = svga->ld = 0xff; + + if (svga->readmode) + { + temp = (svga->colournocare & 1) ? 0xff : 0; + temp &= svga->la; + temp ^= (svga->colourcompare & 1) ? 0xff : 0; + temp2 = (svga->colournocare & 2) ? 0xff : 0; + temp2 &= svga->lb; + temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; + temp3 = (svga->colournocare & 4) ? 0xff : 0; + temp3 &= svga->lc; + temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; + temp4 = (svga->colournocare & 8) ? 0xff : 0; + temp4 &= svga->ld; + temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } +//pclog("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane); + return svga->vram[addr | readplane]; +} + +void svga_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t vala, valb, valc, vald, wm = svga->writemask; + int writemask2 = svga->writemask; + uint32_t raddr = addr; + int plane, mask; + + if (!svga->enablevram) return; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egawrites++; + + if (svga_output) pclog("Write LFB %08X %02X ", addr, val); + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + if (svga->chain4 || svga->fb_only) + { + writemask2=1<<(addr&3); + addr&=~3; + } + else if (svga->chain2_write) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + mask = (1 << plane); + if (svga->seqregs[2] & mask) + { + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) return; + if ((raddr <= 0xA0000) || (raddr >= 0xBFFFF)) return; + svga->vram[addr] = val; + + svga->changedvram[addr >> 12] = changeframecount; + } + return; + } + else + { + addr<<=2; + } + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + if (svga_output) pclog("%08X\n", addr); + svga->changedvram[addr >> 12]=changeframecount; + + switch (svga->writemode) + { + case 1: + if (writemask2 & 1) svga->vram[addr] = svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; + break; + case 0: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = val; + if (writemask2 & 2) svga->vram[addr | 0x1] = val; + if (writemask2 & 4) svga->vram[addr | 0x2] = val; + if (writemask2 & 8) svga->vram[addr | 0x3] = val; + } + else + { + if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + } + break; + case 3: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= val; + + vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + svga->gdcreg[8] = wm; + break; + } +} + +uint8_t svga_read_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t temp, temp2, temp3, temp4; + int readplane = svga->readplane; + int plane; + + if (!svga->enablevram) return 0xff; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egareads++; + + if (svga->chain4 || svga->fb_only) + { + addr &= 0x7fffff; + if (addr >= svga->vram_limit) + return 0xff; + return svga->vram[addr & 0x7fffff]; + } + else if (svga->chain2_read) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xff; + if (addr >= svga->vram_limit) return 0xff; + return svga->vram[addr]; + } + else + addr<<=2; + + addr &= 0x7fffff; + + if ((!svga->extvram) && (addr >= 0x10000)) return 0xff; + + if (addr >= svga->vram_limit) + return 0xff; + + svga->la = svga->vram[addr]; + svga->lb = svga->vram[addr | 0x1]; + svga->lc = svga->vram[addr | 0x2]; + svga->ld = svga->vram[addr | 0x3]; + if (svga->readmode) + { + temp = (svga->colournocare & 1) ? 0xff : 0; + temp &= svga->la; + temp ^= (svga->colourcompare & 1) ? 0xff : 0; + temp2 = (svga->colournocare & 2) ? 0xff : 0; + temp2 &= svga->lb; + temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; + temp3 = (svga->colournocare & 4) ? 0xff : 0; + temp3 &= svga->lc; + temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; + temp4 = (svga->colournocare & 8) ? 0xff : 0; + temp4 &= svga->ld; + temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } +//printf("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane); + return svga->vram[addr | readplane]; +} + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) +{ + int y_add = (enable_overscan) ? 32 : 0; + int x_add = (enable_overscan) ? 16 : 0; + uint32_t *p, *q, i, j; + +// pclog("svga_doblit start\n"); + svga->frames++; +// pclog("doblit %i %i\n", y1, y2); +// pclog("svga_doblit %i %i\n", wx, svga->hdisp); + + + if (y1 > y2) + { + video_blit_memtoscreen(32, 0, 0, 0, xsize + x_add, ysize + y_add); + return; + } + + if ((wx!=xsize || wy!=ysize) && !vid_resize) + { + xsize=wx; + ysize=wy+1; + if (xsize<64) xsize=640; + if (ysize<32) ysize=200; + + updatewindowsize(xsize + x_add,ysize + y_add); + } + if (vid_resize) + { + xsize = wx; + ysize = wy + 1; + } + + if (enable_overscan) + { + if ((wx >= 160) && ((wy + 1) >= 120)) + { + for (i = 0; i < 16; i++) + { + p = &((uint32_t *)buffer32->line[i])[32]; + q = &((uint32_t *)buffer32->line[ysize + y_add - 1 - i])[32]; + + for (j = 0; j < (xsize + x_add); j++) + { + p[j] = svga->pallook[svga->attrregs[0x11]]; + q[j] = svga->pallook[svga->attrregs[0x11]]; + } + } + + for (i = 16; i < (ysize + 16); i ++) + { + p = &((uint32_t *)buffer32->line[i])[32]; + + for (j = 0; j < 8; j++) + { + p[j] = svga->pallook[svga->attrregs[0x11]]; + p[xsize + x_add - 1 - j] = svga->pallook[svga->attrregs[0x11]]; + } + } + } + } + + video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); +// pclog("svga_doblit end\n"); +} + +void svga_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return; + + if (!svga->fast) + { + svga_write(addr, val, p); + svga_write(addr + 1, val >> 8, p); + return; + } + + egawrites += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + + if (svga_output) pclog("svga_writew: %05X ", addr); + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + if (svga_output) pclog("%08X (%i, %i) %04X\n", addr, addr & 1023, addr >> 10, val); + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; +} + +void svga_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return; + + if (!svga->fast) + { + svga_write(addr, val, p); + svga_write(addr + 1, val >> 8, p); + svga_write(addr + 2, val >> 16, p); + svga_write(addr + 3, val >> 24, p); + return; + } + + egawrites += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + + if (svga_output) pclog("svga_writel: %05X ", addr); + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + if (svga_output) pclog("%08X (%i, %i) %08X\n", addr, addr & 1023, addr >> 10, val); + + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; +} + +uint16_t svga_readw(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return 0xffff; + + if (!svga->fast) + return svga_read(addr, p) | (svga_read(addr + 1, p) << 8); + + egareads += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + +// pclog("Readw %05X ", addr); + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xffff; +// pclog("%08X %04X\n", addr, *(uint16_t *)&vram[addr]); + if (addr >= svga->vram_limit) return 0xffff; + + return *(uint16_t *)&svga->vram[addr]; +} + +uint32_t svga_readl(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return 0xffffffff; + + if (!svga->fast) + return svga_read(addr, p) | (svga_read(addr + 1, p) << 8) | (svga_read(addr + 2, p) << 16) | (svga_read(addr + 3, p) << 24); + + egareads += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + +// pclog("Readl %05X ", addr); + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xffffffff; +// pclog("%08X %08X\n", addr, *(uint32_t *)&vram[addr]); + if (addr >= svga->vram_limit) return 0xffffffff; + + return *(uint32_t *)&svga->vram[addr]; +} + +void svga_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return; + + if (!svga->fast) + { + svga_write_linear(addr, val, p); + svga_write_linear(addr + 1, val >> 8, p); + return; + } + + egawrites += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + + if (svga_output) pclog("Write LFBw %08X %04X\n", addr, val); + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; +} + +void svga_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return; + + if (!svga->fast) + { + svga_write_linear(addr, val, p); + svga_write_linear(addr + 1, val >> 8, p); + svga_write_linear(addr + 2, val >> 16, p); + svga_write_linear(addr + 3, val >> 24, p); + return; + } + + egawrites += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + + if (svga_output) pclog("Write LFBl %08X %08X\n", addr, val); + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; +} + +uint16_t svga_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return 0xffff; + + if (!svga->fast) + return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8); + + egareads += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xffff; + if (addr >= svga->vram_limit) return 0xffff; + + return *(uint16_t *)&svga->vram[addr]; +} + +uint32_t svga_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return 0xffffffff; + + if (!svga->fast) + return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8) | (svga_read_linear(addr + 2, p) << 16) | (svga_read_linear(addr + 3, p) << 24); + + egareads += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xffffffff; + if (addr >= svga->vram_limit) return 0xffffffff; + + return *(uint32_t *)&svga->vram[addr]; +} + + +void svga_add_status_info(char *s, int max_len, void *p) +{ + svga_t *svga = (svga_t *)p; + char temps[128]; + + if (svga->chain4) strcpy(temps, "SVGA chained (possibly mode 13h)\n"); + else strcpy(temps, "SVGA unchained (possibly mode-X)\n"); + strncat(s, temps, max_len); + + if (!svga->video_bpp) strcpy(temps, "SVGA in text mode\n"); + else sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames); + svga->frames = 0; + strncat(s, temps, max_len); +} diff --git a/src/vid_svga.h b/src/vid_svga.h new file mode 100644 index 000000000..5b9644bc0 --- /dev/null +++ b/src/vid_svga.h @@ -0,0 +1,154 @@ +typedef struct svga_t +{ + mem_mapping_t mapping; + + uint8_t crtcreg; + uint8_t crtc[128]; + uint8_t gdcreg[16]; + int gdcaddr; + uint8_t attrregs[32]; + int attraddr, attrff; + int attr_palette_enable; + uint8_t seqregs[64]; + int seqaddr; + + uint8_t miscout; + int vidclock; + + uint32_t vram_limit; + + uint8_t la, lb, lc, ld; + + uint8_t dac_mask, dac_status; + int dac_read, dac_write, dac_pos; + int dac_r, dac_g; + + uint8_t cgastat; + + uint8_t plane_mask; + + int fb_only; + + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + int chain4, chain2_write, chain2_read; + int oddeven_page; + int enablevram, extvram; + uint8_t writemask; + uint32_t charseta, charsetb; + + uint8_t egapal[16]; + uint32_t pallook[256]; + PALETTE vgapal; + + int ramdac_type; + + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int linedbl, rowcount; + double clock; + uint32_t ma_latch; + int bpp; + + int dispontime, dispofftime; + int vidtime; + + uint8_t scrblank; + + int dispon; + int hdisp_on; + + uint32_t ma, maback, ca; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink; + int scrollcache; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + + uint8_t *vram; + uint8_t *changedvram; + int vrammask; + uint32_t banked_mask; + + uint32_t write_bank, read_bank; + + int fullchange; + + int video_res_x, video_res_y, video_bpp; + int frames, fps; + + struct + { + int ena; + int x, y; + int xoff, yoff; + int ysize; + uint32_t addr; + int v_acc, h_acc; + } hwcursor, hwcursor_latch, overlay, overlay_latch; + + int hwcursor_on; + int overlay_on; + + int hwcursor_oddeven; + int overlay_oddeven; + + void (*render)(struct svga_t *svga); + void (*recalctimings_ex)(struct svga_t *svga); + + void (*video_out)(uint16_t addr, uint8_t val, void *p); + uint8_t (*video_in) (uint16_t addr, void *p); + + void (*hwcursor_draw)(struct svga_t *svga, int displine); + + void (*overlay_draw)(struct svga_t *svga, int displine); + + /*If set then another device is driving the monitor output and the SVGA + card should not attempt to display anything */ + int override; + void *p; +} svga_t; + +extern int svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)); +extern void svga_recalctimings(svga_t *svga); + + +uint8_t svga_read(uint32_t addr, void *p); +uint16_t svga_readw(uint32_t addr, void *p); +uint32_t svga_readl(uint32_t addr, void *p); +void svga_write(uint32_t addr, uint8_t val, void *p); +void svga_writew(uint32_t addr, uint16_t val, void *p); +void svga_writel(uint32_t addr, uint32_t val, void *p); +uint8_t svga_read_linear(uint32_t addr, void *p); +uint16_t svga_readw_linear(uint32_t addr, void *p); +uint32_t svga_readl_linear(uint32_t addr, void *p); +void svga_write_linear(uint32_t addr, uint8_t val, void *p); +void svga_writew_linear(uint32_t addr, uint16_t val, void *p); +void svga_writel_linear(uint32_t addr, uint32_t val, void *p); + +void svga_add_status_info(char *s, int max_len, void *p); + +extern uint8_t svga_rotate[8][256]; + +void svga_out(uint16_t addr, uint8_t val, void *p); +uint8_t svga_in(uint16_t addr, void *p); + +svga_t *svga_get_pri(); +void svga_set_override(svga_t *svga, int val); + +#define RAMDAC_6BIT 0 +#define RAMDAC_8BIT 1 +void svga_set_ramdac_type(svga_t *svga, int type); + +extern uint8_t mask_crtc[0x19]; diff --git a/src/vid_svga_render.c b/src/vid_svga_render.c new file mode 100644 index 000000000..7ffde9393 --- /dev/null +++ b/src/vid_svga_render.c @@ -0,0 +1,744 @@ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include + +void svga_render_blank(svga_t *svga) +{ + int x, xx; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x < svga->hdisp; x++) + { + switch (svga->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 9) + xx + 32 + x_add] = 0; + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 8) + xx + 32 + x_add] = 0; + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 18) + xx + 32 + x_add] = 0; + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 16) + xx + 32 + x_add] = 0; + break; + } + } +} + +void svga_render_text_40(svga_t *svga) +{ + uint32_t addr_ex = 0; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (svga->fullchange) + { + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + int x, xx; + int drawcursor; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; + int xinc = (svga->seqregs[1] & 1) ? 16 : 18; + + for (x = 0; x < svga->hdisp; x += xinc) + { + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + if (svga->oddeven_page) addr_ex |= 0x10000; + chr = svga->vram[(svga->ma << 1) | addr_ex]; + attr = svga->vram[((svga->ma << 1) + 1) | addr_ex]; + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + if (drawcursor) + { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; + } + else + { + fg = svga->pallook[svga->egapal[attr & 15]]; + bg = svga->pallook[svga->egapal[attr >> 4]]; + if (attr & 0x80 && svga->attrregs[0x10] & 8) + { + bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; + if (svga->blink & 16) + fg = bg; + } + } + + dat = svga->vram[charaddr + (svga->sc << 2)]; + if (svga->seqregs[1] & 1) + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + } + else + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[16] = p[17] = bg; + else + p[16] = p[17] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + } + svga->ma &= svga->vrammask; + } +} + +void svga_render_text_80(svga_t *svga) +{ + uint32_t addr_ex = 0; + FILE *f; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (svga->fullchange) + { + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + int x, xx; + int drawcursor; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; + int xinc = (svga->seqregs[1] & 1) ? 8 : 9; + + for (x = 0; x < svga->hdisp; x += xinc) + { + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + if (svga->oddeven_page) addr_ex |= 0x10000; + chr = svga->vram[(svga->ma << 1) | addr_ex]; + attr = svga->vram[((svga->ma << 1) + 1) | addr_ex]; + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + if (drawcursor) + { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; + } + else + { + fg = svga->pallook[svga->egapal[attr & 15]]; + bg = svga->pallook[svga->egapal[attr >> 4]]; + if (attr & 0x80 && svga->attrregs[0x10] & 8) + { + bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; + if (svga->blink & 16) + fg = bg; + } + } + + dat = svga->vram[charaddr + (svga->sc << 2)]; + if (svga->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[8] = bg; + else + p[8] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + } + svga->ma &= svga->vrammask; + } +} + +void svga_render_2bpp_lowres(svga_t *svga) +{ + int changed_offset; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + changed_offset = (svga->ma << 1) >> 12; + else + changed_offset = ((svga->ma << 1) + 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t dat[2]; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + { + dat[0] = svga->vram[(svga->ma << 1) + 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + 0x8001]; + } + else + { + dat[0] = svga->vram[(svga->ma << 1)]; + dat[1] = svga->vram[(svga->ma << 1) + 1]; + } + svga->ma += 4; + svga->ma &= svga->vrammask; + + p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; + + p += 16; + } + } +} + +void svga_render_2bpp_highres(svga_t *svga) +{ + int changed_offset; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + changed_offset = ((svga->ma << 1) | 0x8000) >> 12; + else + changed_offset = (svga->ma << 1) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t dat[2]; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + { + dat[0] = svga->vram[(svga->ma << 1) + 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + 0x8001]; + } + else + { + dat[0] = svga->vram[(svga->ma << 1)]; + dat[1] = svga->vram[(svga->ma << 1) + 1]; + } + svga->ma += 4; + svga->ma &= svga->vrammask; + + p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; + + p += 8; + } + } +} + +void svga_render_4bpp_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t edat[4]; + uint8_t dat; + + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + svga->ma += 4; + svga->ma &= svga->vrammask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 16; + } + } +} + +void svga_render_4bpp_highres(svga_t *svga) +{ + int changed_offset; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + changed_offset = (svga->ma | 0x8000) >> 12; + else + changed_offset = svga->ma >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t edat[4]; + uint8_t dat; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma | 0x8000]); + else + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + svga->ma += 4; + svga->ma &= svga->vrammask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 8; + } + } +} + +void svga_render_8bpp_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vrammask]); + + p[0] = p[1] = svga->pallook[dat & 0xff]; + p[2] = p[3] = svga->pallook[(dat >> 8) & 0xff]; + p[4] = p[5] = svga->pallook[(dat >> 16) & 0xff]; + p[6] = p[7] = svga->pallook[(dat >> 24) & 0xff]; + + svga->ma += 4; + p += 8; + } + svga->ma &= svga->vrammask; + } + + // return NULL; +} + +void svga_render_8bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat; + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vrammask]); + p[0] = svga->pallook[dat & 0xff]; + p[1] = svga->pallook[(dat >> 8) & 0xff]; + p[2] = svga->pallook[(dat >> 16) & 0xff]; + p[3] = svga->pallook[(dat >> 24) & 0xff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vrammask]); + p[4] = svga->pallook[dat & 0xff]; + p[5] = svga->pallook[(dat >> 8) & 0xff]; + p[6] = svga->pallook[(dat >> 16) & 0xff]; + p[7] = svga->pallook[(dat >> 24) & 0xff]; + + svga->ma += 8; + p += 8; + } + svga->ma &= svga->vrammask; + } + + // return NULL; +} + +void svga_render_15bpp_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vrammask; + } +} + +void svga_render_15bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + p[x + 2] = video_15to32[dat & 0xffff]; + p[x + 3] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vrammask]); + p[x + 4] = video_15to32[dat & 0xffff]; + p[x + 5] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vrammask]); + p[x + 6] = video_15to32[dat & 0xffff]; + p[x + 7] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vrammask; + } +} + +void svga_render_16bpp_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vrammask; + } +} + +void svga_render_16bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + p[x + 2] = video_16to32[dat & 0xffff]; + p[x + 3] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vrammask]); + p[x + 4] = video_16to32[dat & 0xffff]; + p[x + 5] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vrammask]); + p[x + 6] = video_16to32[dat & 0xffff]; + p[x + 7] = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vrammask; + } +} + +void svga_render_24bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 3; + svga->ma &= svga->vrammask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + } + } +} + +void svga_render_24bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vrammask]); + p[x] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vrammask]); + p[x + 1] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vrammask]); + p[x + 2] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vrammask]); + p[x + 3] = dat & 0xffffff; + + svga->ma += 12; + } + svga->ma &= svga->vrammask; + } +} + +void svga_render_32bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 4; + svga->ma &= svga->vrammask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + } + } +} + +/*72% + 91%*/ +void svga_render_32bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vrammask]); + p[x] = dat & 0xffffff; + } + svga->ma += 4; + svga->ma &= svga->vrammask; + } +} + +void svga_render_ABGR8888_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vrammask]); + p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + } + svga->ma += 4; + svga->ma &= svga->vrammask; + } +} + +void svga_render_RGBA8888_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vrammask]); + p[x] = dat >> 8; + } + svga->ma += 4; + svga->ma &= svga->vrammask; + } +} diff --git a/src/vid_svga_render.h b/src/vid_svga_render.h new file mode 100644 index 000000000..944d9757b --- /dev/null +++ b/src/vid_svga_render.h @@ -0,0 +1,33 @@ +extern int firstline_draw, lastline_draw; +extern int displine; +extern int sc; + +extern uint32_t ma, ca; +extern int con, cursoron, cgablink; + +extern int scrollcache; + +extern uint8_t edatlookup[4][4]; + +void svga_render_blank(svga_t *svga); +void svga_render_text_40(svga_t *svga); +void svga_render_text_80(svga_t *svga); + +void svga_render_2bpp_lowres(svga_t *svga); +void svga_render_2bpp_highres(svga_t *svga); +void svga_render_4bpp_lowres(svga_t *svga); +void svga_render_4bpp_highres(svga_t *svga); +void svga_render_8bpp_lowres(svga_t *svga); +void svga_render_8bpp_highres(svga_t *svga); +void svga_render_15bpp_lowres(svga_t *svga); +void svga_render_15bpp_highres(svga_t *svga); +void svga_render_16bpp_lowres(svga_t *svga); +void svga_render_16bpp_highres(svga_t *svga); +void svga_render_24bpp_lowres(svga_t *svga); +void svga_render_24bpp_highres(svga_t *svga); +void svga_render_32bpp_lowres(svga_t *svga); +void svga_render_32bpp_highres(svga_t *svga); +void svga_render_ABGR8888_highres(svga_t *svga); +void svga_render_RGBA8888_highres(svga_t *svga); + +extern void (*svga_render)(svga_t *svga); diff --git a/src/vid_tandy.c b/src/vid_tandy.c new file mode 100644 index 000000000..4f81efc6f --- /dev/null +++ b/src/vid_tandy.c @@ -0,0 +1,726 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_tandy.h" + +static int i_filt[8],q_filt[8]; + +typedef struct tandy_t +{ + mem_mapping_t mapping; + mem_mapping_t ram_mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[32]; + int memctrl;//=-1; + uint32_t base; + uint8_t mode, col; + uint8_t stat; + + uint8_t *vram, *b8000; + uint32_t b8000_mask; + + int linepos, displine; + int sc, vc; + int dispon; + int con, coff, cursoron, blink; + int vsynctime, vadj; + uint16_t ma, maback; + + int dispontime, dispofftime, vidtime; + int firstline, lastline; +} tandy_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void tandy_recalcaddress(tandy_t *tandy); +void tandy_recalctimings(tandy_t *tandy); + +void tandy_out(uint16_t addr, uint8_t val, void *p) +{ + tandy_t *tandy = (tandy_t *)p; + uint8_t old; +// pclog("Tandy OUT %04X %02X\n",addr,val); + switch (addr) + { + case 0x3d4: + tandy->crtcreg = val & 0x1f; + return; + case 0x3d5: + old = tandy->crtc[tandy->crtcreg]; + tandy->crtc[tandy->crtcreg] = val & crtcmask[tandy->crtcreg]; + if (old != val) + { + if (tandy->crtcreg < 0xe || tandy->crtcreg > 0x10) + { + fullchange = changeframecount; + tandy_recalctimings(tandy); + } + } + return; + case 0x3d8: + tandy->mode = val; + return; + case 0x3d9: + tandy->col = val; + return; + case 0x3da: + tandy->array_index = val & 0x1f; + break; + case 0x3de: + if (tandy->array_index & 16) + val &= 0xf; + tandy->array[tandy->array_index & 0x1f] = val; + break; + case 0x3df: + tandy->memctrl = val; + tandy_recalcaddress(tandy); + break; + case 0xa0: + mem_mapping_set_addr(&tandy->ram_mapping, ((val >> 1) & 7) * 128 * 1024, 0x20000); + tandy_recalcaddress(tandy); + break; + } +} + +uint8_t tandy_in(uint16_t addr, void *p) +{ + tandy_t *tandy = (tandy_t *)p; +// if (addr!=0x3DA) pclog("Tandy IN %04X\n",addr); + switch (addr) + { + case 0x3d4: + return tandy->crtcreg; + case 0x3d5: + return tandy->crtc[tandy->crtcreg]; + case 0x3da: + return tandy->stat; + } + return 0xFF; +} + +void tandy_recalcaddress(tandy_t *tandy) +{ + if ((tandy->memctrl & 0xc0) == 0xc0) + { + tandy->vram = &ram[((tandy->memctrl & 0x06) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x30) << 11) + tandy->base]; + tandy->b8000_mask = 0x7fff; +// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x6)<<14)+tandy->base,((tandy->memctrl&0x30)<<11)+tandy->base); + } + else + { + tandy->vram = &ram[((tandy->memctrl & 0x07) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x38) << 11) + tandy->base]; + tandy->b8000_mask = 0x3fff; +// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x7)<<14)+tandy->base,((tandy->memctrl&0x38)<<11)+tandy->base); + } +} + +void tandy_ram_write(uint32_t addr, uint8_t val, void *p) +{ + tandy_t *tandy = (tandy_t *)p; +// pclog("Tandy RAM write %05X %02X %04X:%04X\n",addr,val,CS,pc); + ram[tandy->base + (addr & 0x1ffff)] = val; +} + +uint8_t tandy_ram_read(uint32_t addr, void *p) +{ + tandy_t *tandy = (tandy_t *)p; +// pclog("Tandy RAM read %05X %02X %04X:%04X\n",addr,ram[tandy->base + (addr & 0x1ffff)],CS,pc); + return ram[tandy->base + (addr & 0x1ffff)]; +} + +void tandy_write(uint32_t addr, uint8_t val, void *p) +{ + tandy_t *tandy = (tandy_t *)p; + if (tandy->memctrl == -1) + return; + + egawrites++; +// pclog("Tandy VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI); + tandy->b8000[addr & tandy->b8000_mask] = val; +} + +uint8_t tandy_read(uint32_t addr, void *p) +{ + tandy_t *tandy = (tandy_t *)p; + if (tandy->memctrl == -1) + return 0xff; + + egareads++; +// pclog("Tandy VRAM read %05X %02X %04X:%04X\n",addr,tandy->b8000[addr&0x7FFF],CS,pc); + return tandy->b8000[addr & tandy->b8000_mask]; +} + +void tandy_recalctimings(tandy_t *tandy) +{ + double _dispontime, _dispofftime, disptime; + if (tandy->mode & 1) + { + disptime = tandy->crtc[0] + 1; + _dispontime = tandy->crtc[1]; + } + else + { + disptime = (tandy->crtc[0] + 1) << 1; + _dispontime = tandy->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + tandy->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + tandy->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +/*static int cga4pal[8][4]= +{ + {0,2,4,6},{0,3,5,7},{0,3,4,7},{0,3,4,7}, + {0,10,12,14},{0,11,13,15},{0,11,12,15},{0,11,12,15} +};*/ + +void tandy_poll(void *p) +{ +// int *cgapal=cga4pal[((tandy->col&0x10)>>2)|((cgamode&4)>>1)|((cgacol&0x20)>>5)]; + tandy_t *tandy = (tandy_t *)p; + uint16_t ca = (tandy->crtc[15] | (tandy->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + int y_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, y_val, y_tot; + int i_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, i_val, i_tot; + int q_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, q_val, q_tot; + int r, g, b; + if (!tandy->linepos) + { +// cgapal[0]=tandy->col&15; +// printf("Firstline %i Lastline %i tandy->displine %i\n",firstline,lastline,tandy->displine); + tandy->vidtime += tandy->dispofftime; + tandy->stat |= 1; + tandy->linepos = 1; + oldsc = tandy->sc; + if ((tandy->crtc[8] & 3) == 3) + tandy->sc = (tandy->sc << 1) & 7; + if (tandy->dispon) + { + if (tandy->displine < tandy->firstline) + { + tandy->firstline = tandy->displine; +// printf("Firstline %i\n",firstline); + } + tandy->lastline = tandy->displine; + cols[0] = (tandy->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) + { + if (tandy->array[3] & 4) + { + buffer->line[tandy->displine][c] = cols[0]; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = cols[0]; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = cols[0]; + } + else if ((tandy->mode & 0x12) == 0x12) + { + buffer->line[tandy->displine][c] = 0; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = 0; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[tandy->displine][c] = (tandy->col & 15) + 16; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = (tandy->col & 15) + 16; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = (tandy->col & 15) + 16; + } + } +// printf("X %i %i\n",c+(crtc[1]<<4)+8,c+(crtc[1]<<3)+8); +// printf("Drawing %i %i %i\n",tandy->displine,vc,sc); + if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + buffer->line[tandy->displine][(x << 3) + 8] = + buffer->line[tandy->displine][(x << 3) + 9] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 10] = + buffer->line[tandy->displine][(x << 3) + 11] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 12] = + buffer->line[tandy->displine][(x << 3) + 13] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 14] = + buffer->line[tandy->displine][(x << 3) + 15] = tandy->array[(dat & tandy->array[1]) + 16] + 16; + } + } + else if (tandy->array[3] & 0x10) /*160x200x16*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + buffer->line[tandy->displine][(x << 4) + 8] = + buffer->line[tandy->displine][(x << 4) + 9] = + buffer->line[tandy->displine][(x << 4) + 10] = + buffer->line[tandy->displine][(x << 4) + 11] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 12] = + buffer->line[tandy->displine][(x << 4) + 13] = + buffer->line[tandy->displine][(x << 4) + 14] = + buffer->line[tandy->displine][(x << 4) + 15] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 16] = + buffer->line[tandy->displine][(x << 4) + 17] = + buffer->line[tandy->displine][(x << 4) + 18] = + buffer->line[tandy->displine][(x << 4) + 19] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 20] = + buffer->line[tandy->displine][(x << 4) + 21] = + buffer->line[tandy->displine][(x << 4) + 22] = + buffer->line[tandy->displine][(x << 4) + 23] = tandy->array[(dat & tandy->array[1]) + 16] + 16; + } + } + else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 8; c++) + { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[tandy->displine][(x << 3) + 8 + c] = tandy->array[(chr & tandy->array[1]) + 16] + 16; + dat <<= 1; + } + } + } + else if (tandy->mode & 1) + { + for (x = 0; x < tandy->crtc[1]; x++) + { + chr = tandy->vram[ (tandy->ma << 1) & 0x3fff]; + attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff]; + drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron); + if (tandy->mode & 0x20) + { + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16; + if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16; + } + if (tandy->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } +// if (!((ma^(crtc[15]|(crtc[14]<<8)))&0x3FFF)) printf("Cursor match! %04X\n",ma); + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] ^= 15; + } + tandy->ma++; + } + } + else if (!(tandy->mode & 2)) + { + for (x = 0; x < tandy->crtc[1]; x++) + { + chr = tandy->vram[ (tandy->ma << 1) & 0x3fff]; + attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff]; + drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron); + if (tandy->mode & 0x20) + { + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16; + if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16; + } + tandy->ma++; + if (tandy->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) + { + for (c = 0; c < 16; c++) + buffer->line[tandy->displine][(x << 4) + c + 8] ^= 15; + } + } + } + else if (!(tandy->mode& 16)) + { + cols[0] = (tandy->col & 15) | 16; + col = (tandy->col & 16) ? 24 : 16; + if (tandy->mode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (tandy->col & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + cols[0] = 0; + cols[1] = tandy->array[(tandy->col & tandy->array[1]) + 16] + 16; + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[tandy->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + if (tandy->array[3] & 4) + { + if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, (tandy->array[2] & 0xf) + 16); + else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, (tandy->array[2] & 0xf) + 16); + } + else + { + cols[0] = ((tandy->mode & 0x12) == 0x12) ? 0 : (tandy->col & 0xf) + 16; + if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, cols[0]); + } + } + if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; + else x = (tandy->crtc[1] << 4) + 16; + if (cga_comp) + { + for (c = 0; c < x; c++) + { + y_buf[(c << 1) & 6] = ntsc_col[buffer->line[tandy->displine][c] & 7][(c << 1) & 6] ? 0x6000 : 0; + y_buf[(c << 1) & 6] += (buffer->line[tandy->displine][c] & 8) ? 0x3000 : 0; + i_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * i_filt[(c << 1) & 6]; + q_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * q_filt[(c << 1) & 6]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + + y_buf[((c << 1) & 6) + 1] = ntsc_col[buffer->line[tandy->displine][c] & 7][((c << 1) & 6) + 1] ? 0x6000 : 0; + y_buf[((c << 1) & 6) + 1] += (buffer->line[tandy->displine][c] & 8) ? 0x3000 : 0; + i_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * i_filt[((c << 1) & 6) + 1]; + q_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * q_filt[((c << 1) & 6) + 1]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + if (r > 511) r = 511; + if (g > 511) g = 511; + if (b > 511) b = 511; + + ((uint32_t *)buffer32->line[tandy->displine])[c] = makecol32(r / 2, g / 2, b / 2); + } + } + tandy->sc = oldsc; + if (tandy->vc == tandy->crtc[7] && !tandy->sc) + { + tandy->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + tandy->displine++; + if (tandy->displine >= 360) + tandy->displine = 0; + } + else + { + tandy->vidtime += tandy->dispontime; + if (tandy->dispon) + tandy->stat &= ~1; + tandy->linepos = 0; + if (tandy->vsynctime) + { + tandy->vsynctime--; + if (!tandy->vsynctime) + { + tandy->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (tandy->sc == (tandy->crtc[11] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[11] & 31) >> 1))) + { + tandy->con = 0; + tandy->coff = 1; + } + if (tandy->vadj) + { + tandy->sc++; + tandy->sc &= 31; + tandy->ma = tandy->maback; + tandy->vadj--; + if (!tandy->vadj) + { + tandy->dispon = 1; + tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff; + tandy->sc = 0; +// printf("Display on!\n"); + } + } + else if (tandy->sc == tandy->crtc[9] || ((tandy->crtc[8] & 3) == 3 && tandy->sc == (tandy->crtc[9] >> 1))) + { + tandy->maback = tandy->ma; +// con=0; +// coff=0; + tandy->sc = 0; + oldvc = tandy->vc; + tandy->vc++; + tandy->vc &= 127; +// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],tandy->dispon); + if (tandy->vc == tandy->crtc[6]) + tandy->dispon = 0; + if (oldvc == tandy->crtc[4]) + { +// printf("Display over at %i\n",tandy->displine); + tandy->vc = 0; + tandy->vadj = tandy->crtc[5]; + if (!tandy->vadj) + tandy->dispon = 1; + if (!tandy->vadj) + tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff; + if ((tandy->crtc[10] & 0x60) == 0x20) tandy->cursoron = 0; + else tandy->cursoron = tandy->blink & 16; +// printf("CRTC10 %02X %i\n",crtc[10],cursoron); + } + if (tandy->vc == tandy->crtc[7]) + { + tandy->dispon = 0; + tandy->displine = 0; + tandy->vsynctime = 16;//(crtc[3]>>4)+1; +// printf("tandy->vsynctime %i %02X\n",tandy->vsynctime,crtc[3]); +// tandy->stat|=8; + if (tandy->crtc[7]) + { +// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize); + if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; + else x = (tandy->crtc[1] << 4) + 16; + tandy->lastline++; + if (x != xsize || (tandy->lastline - tandy->firstline) != ysize) + { + xsize = x; + ysize = tandy->lastline - tandy->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtc[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } +// printf("Blit %i %i\n",firstline,lastline); +//printf("Xsize is %i\n",xsize); + startblit(); + if (cga_comp) + video_blit_memtoscreen(0, tandy->firstline-4, 0, (tandy->lastline - tandy->firstline) + 8, xsize, (tandy->lastline - tandy->firstline) + 8); + else + video_blit_memtoscreen_8(0, tandy->firstline-4, xsize, (tandy->lastline - tandy->firstline) + 8); + endblit(); + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ + { + video_res_x /= 2; + video_bpp = 4; + } + else if (tandy->array[3] & 0x10) /*160x200x16*/ + { + video_res_x /= 4; + video_bpp = 4; + } + else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ + video_bpp = 2; + else if (tandy->mode & 1) + { + video_res_x /= 8; + video_res_y /= tandy->crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy->mode & 2)) + { + video_res_x /= 16; + video_res_y /= tandy->crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy->mode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + video_bpp = 1; + } + tandy->firstline = 1000; + tandy->lastline = 0; + tandy->blink++; + } + } + else + { + tandy->sc++; + tandy->sc &= 31; + tandy->ma = tandy->maback; + } + if ((tandy->sc == (tandy->crtc[10] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[10] & 31) >> 1)))) + tandy->con = 1; + } +} + +void *tandy_init() +{ + int c; + int tandy_tint = -2; + tandy_t *tandy = malloc(sizeof(tandy_t)); + memset(tandy, 0, sizeof(tandy_t)); + + tandy->memctrl = -1; + tandy->base = (mem_size - 128) * 1024; + + for (c = 0; c < 8; c++) + { + i_filt[c] = 512.0 * cos((3.14 * (tandy_tint + c * 4) / 16.0) - 33.0 / 180.0); + q_filt[c] = 512.0 * sin((3.14 * (tandy_tint + c * 4) / 16.0) - 33.0 / 180.0); + } + timer_add(tandy_poll, &tandy->vidtime, TIMER_ALWAYS_ENABLED, tandy); + mem_mapping_add(&tandy->mapping, 0xb8000, 0x08000, tandy_read, NULL, NULL, tandy_write, NULL, NULL, NULL, 0, tandy); + mem_mapping_add(&tandy->ram_mapping, 0x80000, 0x20000, tandy_ram_read, NULL, NULL, tandy_ram_write, NULL, NULL, NULL, 0, tandy); + /*Base 128k mapping is controlled via port 0xA0, so we remove it from the main mapping*/ + mem_mapping_set_addr(&ram_low_mapping, 0, (mem_size - 128) * 1024); + io_sethandler(0x03d0, 0x0010, tandy_in, NULL, NULL, tandy_out, NULL, NULL, tandy); + io_sethandler(0x00a0, 0x0001, tandy_in, NULL, NULL, tandy_out, NULL, NULL, tandy); + tandy->b8000_mask = 0x3fff; + + overscan_x = overscan_y = 16; + + return tandy; +} + +void tandy_close(void *p) +{ + tandy_t *tandy = (tandy_t *)p; + + free(tandy); +} + +void tandy_speed_changed(void *p) +{ + tandy_t *tandy = (tandy_t *)p; + + tandy_recalctimings(tandy); +} + +device_t tandy_device = +{ + "Tandy 1000 (video)", + 0, + tandy_init, + tandy_close, + NULL, + tandy_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_tandy.h b/src/vid_tandy.h new file mode 100644 index 000000000..67e3bc5cf --- /dev/null +++ b/src/vid_tandy.h @@ -0,0 +1 @@ +extern device_t tandy_device; diff --git a/src/vid_tandysl.c b/src/vid_tandysl.c new file mode 100644 index 000000000..ece4e1fb0 --- /dev/null +++ b/src/vid_tandysl.c @@ -0,0 +1,733 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_tandysl.h" + +typedef struct tandysl_t +{ + mem_mapping_t mapping; + mem_mapping_t ram_mapping; + mem_mapping_t vram_mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[32]; + int memctrl;//=-1; + uint32_t base; + uint8_t mode, col; + uint8_t stat; + + uint8_t *vram, *b8000; + uint32_t b8000_limit; + uint8_t planar_ctrl; + + int linepos, displine; + int sc, vc; + int dispon; + int con, coff, cursoron, blink; + int vsynctime, vadj; + uint16_t ma, maback; + + int dispontime, dispofftime, vidtime; + int firstline, lastline; +} tandysl_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void tandysl_recalcaddress(tandysl_t *tandy); +static void tandysl_recalctimings(tandysl_t *tandy); +static void tandysl_recalcmapping(tandysl_t *tandy); +static uint8_t tandysl_in(uint16_t addr, void *p); +static void tandysl_ram_write(uint32_t addr, uint8_t val, void *p); +static void tandysl_write(uint32_t addr, uint8_t val, void *p); + +static void tandysl_out(uint16_t addr, uint8_t val, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + uint8_t old; +// pclog("TandySL OUT %04X %02X\n",addr,val); + switch (addr) + { + case 0x3d4: + tandy->crtcreg = val & 0x1f; + return; + case 0x3d5: +// pclog("Write CRTC R%02x %02x ",tandy->crtcreg, val); + old = tandy->crtc[tandy->crtcreg]; + tandy->crtc[tandy->crtcreg] = val & crtcmask[tandy->crtcreg]; +// pclog("now %02x\n", tandy->crtc[tandy->crtcreg]); + if (old != val) + { + if (tandy->crtcreg < 0xe || tandy->crtcreg > 0x10) + { + fullchange = changeframecount; + tandysl_recalctimings(tandy); + } + } + return; + case 0x3d8: + tandy->mode = val; + return; + case 0x3d9: + tandy->col = val; + return; + case 0x3da: + tandy->array_index = val & 0x1f; + break; + case 0x3de: + if (tandy->array_index & 16) + val &= 0xf; + tandy->array[tandy->array_index & 0x1f] = val; + if ((tandy->array_index & 0x1f) == 5) + { + tandysl_recalcmapping(tandy); + tandysl_recalcaddress(tandy); + } + break; + case 0x3df: + tandy->memctrl = val; +// pclog("tandy 3df write %02x\n", val); + tandysl_recalcaddress(tandy); + break; + case 0x65: + if (val == 8) /*Hack*/ + return; + tandy->planar_ctrl = val; + tandysl_recalcmapping(tandy); + break; + case 0xffe8: + if ((val & 0xe) == 0xe) + mem_mapping_disable(&tandy->ram_mapping); + else + mem_mapping_set_addr(&tandy->ram_mapping, ((val >> 1) & 7) * 128 * 1024, 0x20000); + tandysl_recalcaddress(tandy); + break; + } +} + +static uint8_t tandysl_in(uint16_t addr, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; +// if (addr!=0x3DA) pclog("Tandy IN %04X\n",addr); + switch (addr) + { + case 0x3d4: + return tandy->crtcreg; + case 0x3d5: + return tandy->crtc[tandy->crtcreg]; + case 0x3da: + return tandy->stat; + } +// pclog("Bad Tandy IN %04x\n", addr); + return 0xFF; +} + +static void tandysl_recalcaddress(tandysl_t *tandy) +{ + tandy->b8000_limit = 0x8000; + if (tandy->array[5] & 1) + { + tandy->vram = &ram[((tandy->memctrl & 0x04) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x20) << 11) + tandy->base]; + } + else if ((tandy->memctrl & 0xc0) == 0xc0) + { + tandy->vram = &ram[((tandy->memctrl & 0x06) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x30) << 11) + tandy->base]; +// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x6)<<14)+tandy->base,((tandy->memctrl&0x30)<<11)+tandy->base); + } + else + { + tandy->vram = &ram[((tandy->memctrl & 0x07) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x38) << 11) + tandy->base]; +// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x7)<<14)+tandy->base,((tandy->memctrl&0x38)<<11)+tandy->base); + if ((tandy->memctrl & 0x38) == 0x38) + tandy->b8000_limit = 0x4000; + } +} + +static void tandysl_recalcmapping(tandysl_t *tandy) +{ + mem_mapping_disable(&tandy->mapping); + io_removehandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + if (tandy->planar_ctrl & 4) + { +// pclog("Enable VRAM mapping\n"); + mem_mapping_enable(&tandy->mapping); + if (tandy->array[5] & 1) + { +// pclog("Tandy mapping at A0000 %p %p\n", tandy_ram_write, tandy_write); + mem_mapping_set_addr(&tandy->mapping, 0xa0000, 0x10000); + } + else + { +// pclog("Tandy mapping at B8000\n"); + mem_mapping_set_addr(&tandy->mapping, 0xb8000, 0x8000); + } +// mem_mapping_enable(&tandy->vram_mapping); + io_sethandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + } + else + { +// pclog("Disable VRAM mapping\n"); + mem_mapping_disable(&tandy->mapping); +// mem_mapping_disable(&tandy->vram_mapping); + io_removehandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + } +} +static void tandysl_ram_write(uint32_t addr, uint8_t val, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; +// pclog("Tandy RAM write %05X %02X %04X:%04X %08x\n",addr,val,CS,pc, tandy->base); + ram[tandy->base + (addr & 0x1ffff)] = val; +} + +static uint8_t tandysl_ram_read(uint32_t addr, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; +// if (!nopageerrors) pclog("Tandy RAM read %05X %02X %04X:%04X\n",addr,ram[tandy->base + (addr & 0x1ffff)],CS,pc); + return ram[tandy->base + (addr & 0x1ffff)]; +} + +static void tandysl_write(uint32_t addr, uint8_t val, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + if (tandy->memctrl == -1) + return; + + egawrites++; +// pclog("Tandy VRAM write %05X %02X %04X:%04X %02x %x\n",addr,val,CS,pc,tandy->array[5], (uintptr_t)&tandy->b8000[addr & 0xffff] - (uintptr_t)ram); + if (tandy->array[5] & 1) + tandy->b8000[addr & 0xffff] = val; + else + { + if ((addr & 0x7fff) >= tandy->b8000_limit) + return; + tandy->b8000[addr & 0x7fff] = val; + } +} + +static uint8_t tandysl_read(uint32_t addr, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + if (tandy->memctrl == -1) + return 0xff; + + egareads++; +// if (!nopageerrors) pclog("Tandy VRAM read %05X %02X %04X:%04X\n",addr,tandy->b8000[addr&0x7FFF],CS,pc); + if (tandy->array[5] & 1) + return tandy->b8000[addr & 0xffff]; + if ((addr & 0x7fff) >= tandy->b8000_limit) + return 0xff; + return tandy->b8000[addr & 0x7fff]; +} + +static void tandysl_recalctimings(tandysl_t *tandy) +{ + double _dispontime, _dispofftime, disptime; + if (tandy->mode & 1) + { + disptime = tandy->crtc[0] + 1; + _dispontime = tandy->crtc[1]; + } + else + { + disptime = (tandy->crtc[0] + 1) << 1; + _dispontime = tandy->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + tandy->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + tandy->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void tandysl_poll(void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + uint16_t ca = (tandy->crtc[15] | (tandy->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + + if (!tandy->linepos) + { +// pclog("tandy_poll vc=%i sc=%i dispon=%i\n", tandy->vc, tandy->sc, tandy->dispon); +// cgapal[0]=tandy->col&15; +// printf("Firstline %i Lastline %i tandy->displine %i\n",firstline,lastline,tandy->displine); + tandy->vidtime += tandy->dispofftime; + tandy->stat |= 1; + tandy->linepos = 1; + oldsc = tandy->sc; + if ((tandy->crtc[8] & 3) == 3) + tandy->sc = (tandy->sc << 1) & 7; + if (tandy->dispon) + { + if (tandy->displine < tandy->firstline) + { + tandy->firstline = tandy->displine; +// printf("Firstline %i\n",firstline); + } + tandy->lastline = tandy->displine; + cols[0] = (tandy->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) + { + if (tandy->array[3] & 4) + { + buffer->line[tandy->displine][c] = cols[0]; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = cols[0]; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = cols[0]; + } + else if ((tandy->mode & 0x12) == 0x12) + { + buffer->line[tandy->displine][c] = 0; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = 0; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[tandy->displine][c] = (tandy->col & 15) + 16; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = (tandy->col & 15) + 16; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = (tandy->col & 15) + 16; + } + } + if (tandy->array[5] & 1) /*640x200x16*/ + { + for (x = 0; x < tandy->crtc[1]*2; x++) + { + dat = (tandy->vram[(tandy->ma << 1) & 0xffff] << 8) | + tandy->vram[((tandy->ma << 1) + 1) & 0xffff]; + tandy->ma++; + buffer->line[tandy->displine][(x << 2) + 8] = tandy->array[((dat >> 12) & 0xf)/*tandy->array[1])*/ + 16] + 16; + buffer->line[tandy->displine][(x << 2) + 9] = tandy->array[((dat >> 8) & 0xf)/*tandy->array[1])*/ + 16] + 16; + buffer->line[tandy->displine][(x << 2) + 10] = tandy->array[((dat >> 4) & 0xf)/*tandy->array[1])*/ + 16] + 16; + buffer->line[tandy->displine][(x << 2) + 11] = tandy->array[(dat & 0xf)/*tandy->array[1])*/ + 16] + 16; + } + } + else if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + buffer->line[tandy->displine][(x << 3) + 8] = + buffer->line[tandy->displine][(x << 3) + 9] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 10] = + buffer->line[tandy->displine][(x << 3) + 11] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 12] = + buffer->line[tandy->displine][(x << 3) + 13] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 14] = + buffer->line[tandy->displine][(x << 3) + 15] = tandy->array[(dat & tandy->array[1]) + 16] + 16; + } + } + else if (tandy->array[3] & 0x10) /*160x200x16*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + buffer->line[tandy->displine][(x << 4) + 8] = + buffer->line[tandy->displine][(x << 4) + 9] = + buffer->line[tandy->displine][(x << 4) + 10] = + buffer->line[tandy->displine][(x << 4) + 11] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 12] = + buffer->line[tandy->displine][(x << 4) + 13] = + buffer->line[tandy->displine][(x << 4) + 14] = + buffer->line[tandy->displine][(x << 4) + 15] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 16] = + buffer->line[tandy->displine][(x << 4) + 17] = + buffer->line[tandy->displine][(x << 4) + 18] = + buffer->line[tandy->displine][(x << 4) + 19] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 20] = + buffer->line[tandy->displine][(x << 4) + 21] = + buffer->line[tandy->displine][(x << 4) + 22] = + buffer->line[tandy->displine][(x << 4) + 23] = tandy->array[(dat & tandy->array[1]) + 16] + 16; + } + } + else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 8; c++) + { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[tandy->displine][(x << 3) + 8 + c] = tandy->array[(chr & tandy->array[1]) + 16] + 16; + dat <<= 1; + } + } + } + else if (tandy->mode & 1) + { + for (x = 0; x < tandy->crtc[1]; x++) + { + chr = tandy->vram[ (tandy->ma << 1) & 0x3fff]; + attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff]; + drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron); + if (tandy->mode & 0x20) + { + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16; + if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16; + } + if (tandy->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } +// if (!((ma^(crtc[15]|(crtc[14]<<8)))&0x3FFF)) printf("Cursor match! %04X\n",ma); + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] ^= 15; + } + tandy->ma++; + } + } + else if (!(tandy->mode & 2)) + { + for (x = 0; x < tandy->crtc[1]; x++) + { + chr = tandy->vram[ (tandy->ma << 1) & 0x3fff]; + attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff]; + drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron); + if (tandy->mode & 0x20) + { + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16; + if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16; + } + tandy->ma++; + if (tandy->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) + { + for (c = 0; c < 16; c++) + buffer->line[tandy->displine][(x << 4) + c + 8] ^= 15; + } + } + } + else if (!(tandy->mode& 16)) + { + cols[0] = (tandy->col & 15) | 16; + col = (tandy->col & 16) ? 24 : 16; + if (tandy->mode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (tandy->col & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + cols[0] = 0; + cols[1] = tandy->array[(tandy->col & tandy->array[1]) + 16] + 16; + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[tandy->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + if (tandy->array[3] & 4) + { + if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, (tandy->array[2] & 0xf) + 16); + else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, (tandy->array[2] & 0xf) + 16); + } + else + { + cols[0] = ((tandy->mode & 0x12) == 0x12) ? 0 : (tandy->col & 0xf) + 16; + if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, cols[0]); + } + } + if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; + else x = (tandy->crtc[1] << 4) + 16; + tandy->sc = oldsc; + if (tandy->vc == tandy->crtc[7] && !tandy->sc) + { + tandy->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + tandy->displine++; + if (tandy->displine >= 360) + tandy->displine = 0; + } + else + { + tandy->vidtime += tandy->dispontime; + if (tandy->dispon) + tandy->stat &= ~1; + tandy->linepos = 0; + if (tandy->vsynctime) + { + tandy->vsynctime--; + if (!tandy->vsynctime) + { + tandy->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (tandy->sc == (tandy->crtc[11] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[11] & 31) >> 1))) + { + tandy->con = 0; + tandy->coff = 1; + } + if (tandy->vadj) + { + tandy->sc++; + tandy->sc &= 31; + tandy->ma = tandy->maback; + tandy->vadj--; + if (!tandy->vadj) + { + tandy->dispon = 1; + if (tandy->array[5] & 1) + tandy->ma = tandy->maback = tandy->crtc[13] | (tandy->crtc[12] << 8); + else + tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff; + tandy->sc = 0; +// printf("Display on!\n"); + } + } + else if (tandy->sc == tandy->crtc[9] || ((tandy->crtc[8] & 3) == 3 && tandy->sc == (tandy->crtc[9] >> 1))) + { + tandy->maback = tandy->ma; +// con=0; +// coff=0; + tandy->sc = 0; + oldvc = tandy->vc; + tandy->vc++; + tandy->vc &= 255; +// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],tandy->dispon); + if (tandy->vc == tandy->crtc[6]) + { +// pclog("Display off\n"); + tandy->dispon = 0; + } + if (oldvc == tandy->crtc[4]) + { +// pclog("Display over\n"); +// printf("Display over at %i\n",tandy->displine); + tandy->vc = 0; + tandy->vadj = tandy->crtc[5]; + if (!tandy->vadj) + tandy->dispon = 1; + if (!tandy->vadj) + { + if (tandy->array[5] & 1) + tandy->ma = tandy->maback = tandy->crtc[13] | (tandy->crtc[12] << 8); + else + tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff; + } + if ((tandy->crtc[10] & 0x60) == 0x20) tandy->cursoron = 0; + else tandy->cursoron = tandy->blink & 16; +// printf("CRTC10 %02X %i\n",crtc[10],cursoron); + } + if (tandy->vc == tandy->crtc[7]) + { + tandy->dispon = 0; + tandy->displine = 0; + tandy->vsynctime = 16;//(crtc[3]>>4)+1; +// printf("tandy->vsynctime %i %02X\n",tandy->vsynctime,crtc[3]); +// tandy->stat|=8; + if (tandy->crtc[7]) + { +// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize); + if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; + else x = (tandy->crtc[1] << 4) + 16; + tandy->lastline++; + if (x != xsize || (tandy->lastline - tandy->firstline) != ysize) + { + xsize = x; + ysize = tandy->lastline - tandy->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtc[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } +// printf("Blit %i %i\n",firstline,lastline); +//printf("Xsize is %i\n",xsize); + startblit(); + video_blit_memtoscreen_8(0, tandy->firstline-4, xsize, (tandy->lastline - tandy->firstline) + 8); + endblit(); + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ + { + video_res_x /= 2; + video_bpp = 4; + } + else if (tandy->array[3] & 0x10) /*160x200x16*/ + { + video_res_x /= 4; + video_bpp = 4; + } + else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ + video_bpp = 2; + else if (tandy->mode & 1) + { + video_res_x /= 8; + video_res_y /= tandy->crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy->mode & 2)) + { + video_res_x /= 16; + video_res_y /= tandy->crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy->mode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + video_bpp = 1; + } + tandy->firstline = 1000; + tandy->lastline = 0; + tandy->blink++; + } + } + else + { + tandy->sc++; + tandy->sc &= 31; + tandy->ma = tandy->maback; + } + if ((tandy->sc == (tandy->crtc[10] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[10] & 31) >> 1)))) + tandy->con = 1; + } +} + +static void *tandysl_init() +{ + int c; + tandysl_t *tandy = malloc(sizeof(tandysl_t)); + memset(tandy, 0, sizeof(tandysl_t)); + + tandy->memctrl = -1; + tandy->base = (mem_size - 128) * 1024; + tandy->b8000_limit = 0x8000; + tandy->planar_ctrl = 4; + + timer_add(tandysl_poll, &tandy->vidtime, TIMER_ALWAYS_ENABLED, tandy); + mem_mapping_add(&tandy->mapping, 0xb8000, 0x08000, tandysl_read, NULL, NULL, tandysl_write, NULL, NULL, NULL, 0, tandy); + mem_mapping_add(&tandy->ram_mapping, 0x80000, 0x20000, tandysl_ram_read, NULL, NULL, tandysl_ram_write, NULL, NULL, NULL, 0, tandy); + /*Base 128k mapping is controlled via port 0xffe8, so we remove it from the main mapping*/ + mem_mapping_set_addr(&ram_low_mapping, 0, (mem_size - 128) * 1024); + io_sethandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + io_sethandler(0xffe8, 0x0001, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + io_sethandler(0x0065, 0x0001, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + overscan_x = overscan_y = 16; + return tandy; +} + +static void tandysl_close(void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + + free(tandy); +} + +static void tandysl_speed_changed(void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + + tandysl_recalctimings(tandy); +} + +device_t tandysl_device = +{ + "Tandy 1000SL (video)", + 0, + tandysl_init, + tandysl_close, + NULL, + tandysl_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_tandysl.h b/src/vid_tandysl.h new file mode 100644 index 000000000..5d09cf6ce --- /dev/null +++ b/src/vid_tandysl.h @@ -0,0 +1 @@ +extern device_t tandysl_device; diff --git a/src/vid_tgui9440.c b/src/vid_tgui9440.c new file mode 100644 index 000000000..6af165fd2 --- /dev/null +++ b/src/vid_tgui9440.c @@ -0,0 +1,1333 @@ +/*Trident TGUI9440 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_tkd8001_ramdac.h" +#include "vid_tgui9440.h" + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (tgui->fifo_write_idx - tgui->fifo_read_idx) +#define FIFO_FULL ((tgui->fifo_write_idx - tgui->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (tgui->fifo_read_idx == tgui->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_FB_BYTE = (0x04 << 24), + FIFO_WRITE_FB_WORD = (0x05 << 24), + FIFO_WRITE_FB_LONG = (0x06 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct tgui_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t accel_mapping; + + rom_t bios_rom; + + svga_t svga; + + struct + { + uint16_t src_x, src_y; + uint16_t dst_x, dst_y; + uint16_t size_x, size_y; + uint16_t fg_col, bg_col; + uint8_t rop; + uint16_t flags; + uint8_t pattern[0x80]; + int command; + int offset; + uint8_t ger22; + + int x, y; + uint32_t src, dst, src_old, dst_old; + int pat_x, pat_y; + int use_src; + + int pitch, bpp; + + uint16_t tgui_pattern[8][8]; + } accel; + + uint8_t tgui_3d8, tgui_3d9; + int oldmode; + uint8_t oldctrl2,newctrl2; + + uint32_t linear_base, linear_size; + + int ramdac_state; + uint8_t ramdac_ctrl; + + int clock_m, clock_n, clock_k; + + uint32_t vram_size, vram_mask; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; +} tgui_t; + +void tgui_recalcmapping(tgui_t *tgui); + +static void fifo_thread(void *param); + +uint8_t tgui_accel_read(uint32_t addr, void *priv); +uint16_t tgui_accel_read_w(uint32_t addr, void *priv); +uint32_t tgui_accel_read_l(uint32_t addr, void *priv); + +void tgui_accel_write(uint32_t addr, uint8_t val, void *priv); +void tgui_accel_write_w(uint32_t addr, uint16_t val, void *priv); +void tgui_accel_write_l(uint32_t addr, uint32_t val, void *priv); + + +void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *priv); + +void tgui_out(uint16_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + uint8_t old; + +// pclog("tgui_out : %04X %02X %04X:%04X %i\n", addr, val, CS,pc, svga->bpp); + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + switch (svga->seqaddr & 0xf) + { + case 0xB: + tgui->oldmode=1; + break; + case 0xC: + if (svga->seqregs[0xe] & 0x80) + svga->seqregs[0xc] = val; + break; + case 0xd: + if (tgui->oldmode) + tgui->oldctrl2 = val; + else + tgui->newctrl2=val; + break; + case 0xE: + svga->seqregs[0xe] = val ^ 2; + svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; + if (!(svga->gdcreg[0xf] & 1)) + svga->read_bank = svga->write_bank; + return; + } + break; + + case 0x3C6: + if (tgui->ramdac_state == 4) + { + tgui->ramdac_state = 0; + tgui->ramdac_ctrl = val; + switch (tgui->ramdac_ctrl & 0xf0) + { + case 0x10: + svga->bpp = 15; + break; + case 0x30: + svga->bpp = 16; + break; + case 0xd0: + svga->bpp = 24; + break; + default: + svga->bpp = 8; + break; + } + return; + } + case 0x3C7: case 0x3C8: case 0x3C9: + tgui->ramdac_state = 0; + break; + + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 0x6: + if (svga->gdcreg[6] != val) + { + svga->gdcreg[6] = val; + tgui_recalcmapping(tgui); + } + return; + + case 0xE: + svga->gdcreg[0xe] = val ^ 2; + if ((svga->gdcreg[0xf] & 1) == 1) + svga->read_bank = (svga->gdcreg[0xe] & 0xf) * 65536; + break; + case 0xF: + if (val & 1) svga->read_bank = (svga->gdcreg[0xe] & 0xf) *65536; + else svga->read_bank = (svga->seqregs[0xe] & 0xf) *65536; + svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; + break; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x7f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; +// if (svga->crtcreg != 0xE && svga->crtcreg != 0xF) pclog("CRTC R%02X = %02X\n", svga->crtcreg, val); + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + switch (svga->crtcreg) + { + case 0x21: + if (old != val) + { + if (!PCI) + { + tgui->linear_base = ((val & 0xf) | ((val >> 2) & 0x30)) << 20; + tgui->linear_size = (val & 0x10) ? 0x200000 : 0x100000; + } + tgui_recalcmapping(tgui); + } + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + svga->hwcursor.x = (svga->crtc[0x40] | (svga->crtc[0x41] << 8)) & 0x7ff; + svga->hwcursor.y = (svga->crtc[0x42] | (svga->crtc[0x43] << 8)) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x46] & 0x3f; + svga->hwcursor.yoff = svga->crtc[0x47] & 0x3f; + svga->hwcursor.addr = (svga->crtc[0x44] << 10) | ((svga->crtc[0x45] & 0x7) << 18) | (svga->hwcursor.yoff * 8); + break; + + case 0x50: + svga->hwcursor.ena = val & 0x80; + break; + } + return; + case 0x3D8: + tgui->tgui_3d8 = val; + if (svga->gdcreg[0xf] & 4) + { + svga->write_bank = (val & 0x1f) * 65536; +// pclog("SVGAWBANK 3D8 %08X %04X:%04X\n",svgawbank,CS,pc); + if (!(svga->gdcreg[0xf] & 1)) + { + svga->read_bank = (val & 0x1f) * 65536; +// pclog("SVGARBANK 3D8 %08X %04X:%04X\n",svgarbank,CS,pc); + } + } + return; + case 0x3D9: + tgui->tgui_3d9 = val; + if ((svga->gdcreg[0xf] & 5) == 5) + { + svga->read_bank = (val & 0x1F) * 65536; +// pclog("SVGARBANK 3D9 %08X %04X:%04X\n",svgarbank,CS,pc); + } + return; + + case 0x43c8: + tgui->clock_n = val & 0x7f; + tgui->clock_m = (tgui->clock_m & ~1) | (val >> 7); + break; + case 0x43c9: + tgui->clock_m = (tgui->clock_m & ~0x1e) | ((val << 1) & 0x1e); + tgui->clock_k = (val & 0x10) >> 4; + break; + } + svga_out(addr, val, svga); +} + +uint8_t tgui_in(uint16_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + +// if (addr != 0x3da) pclog("tgui_in : %04X %04X:%04X\n", addr, CS,pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 0xb) + { +// printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); + tgui->oldmode = 0; + return 0xe3; /*TGUI9440AGi*/ + } + if ((svga->seqaddr & 0xf) == 0xc) + { +// printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); +// return 0x20; /*2 DRAM banks*/ + } + if ((svga->seqaddr & 0xf) == 0xd) + { + if (tgui->oldmode) return tgui->oldctrl2; + return tgui->newctrl2; + } + break; + case 0x3C6: + if (tgui->ramdac_state == 4) + return tgui->ramdac_ctrl; + tgui->ramdac_state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + tgui->ramdac_state = 0; + break; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + case 0x3d8: + return tgui->tgui_3d8; + case 0x3d9: + return tgui->tgui_3d9; + } + return svga_in(addr, svga); +} + +void tgui_recalctimings(svga_t *svga) +{ + tgui_t *tgui = (tgui_t *)svga->p; + + if (svga->crtc[0x29] & 0x10) + svga->rowoffset += 0x100; + + if (svga->bpp == 24) + svga->hdisp = (svga->crtc[1] + 1) * 8; + + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; + + if (tgui->oldctrl2 & 0x10) + { + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; + } + if (tgui->oldctrl2 & 0x10) /*I'm not convinced this is the right register for this function*/ + svga->lowres=0; + + svga->lowres = !(svga->crtc[0x2a] & 0x40); + + // svga->interlace = svga->crtc[0x1e] & 4; + if (svga->crtc[0x1e] & 4) + { + // svga->rowoffset >>= 1; + svga->vtotal *= 2; + svga->dispend *= 2; + svga->vblankstart *= 2; + svga->vsyncstart *= 2; + svga->split *= 2; + } + + if (svga->miscout & 8) + svga->clock = cpuclock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + + if (svga->gdcreg[0xf] & 0x08) + svga->clock *= 2; + else if (svga->gdcreg[0xf] & 0x40) + svga->clock *= 3; + + if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + } + } +} + +void tgui_recalcmapping(tgui_t *tgui) +{ + svga_t *svga = &tgui->svga; + +// pclog("tgui_recalcmapping : %02X %02X\n", svga->crtc[0x21], svga->gdcreg[6]); + + if (svga->crtc[0x21] & 0x20) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&tgui->linear_mapping, tgui->linear_base, tgui->linear_size); +// pclog("Trident linear framebuffer at %08X - size %06X\n", tgui->linear_base, tgui->linear_size); + mem_mapping_enable(&tgui->accel_mapping); + } + else + { +// pclog("Write mapping %02X\n", val); + mem_mapping_disable(&tgui->linear_mapping); + mem_mapping_disable(&tgui->accel_mapping); + switch (svga->gdcreg[6] & 0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_enable(&tgui->accel_mapping); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } +} + +void tgui_hwcursor_draw(svga_t *svga, int displine) +{ + uint32_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 24) | (svga->vram[svga->hwcursor_latch.addr + 1] << 16) | (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 4] << 24) | (svga->vram[svga->hwcursor_latch.addr + 5] << 16) | (svga->vram[svga->hwcursor_latch.addr + 6] << 8) | svga->vram[svga->hwcursor_latch.addr + 7]; + for (xx = 0; xx < 32; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x80000000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x80000000) ? 0xffffff : 0; + else if (dat[1] & 0x80000000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; +// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]); + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 8; +} + +uint8_t tgui_pci_read(int func, int addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + +// pclog("Trident PCI read %08X\n", addr); + + switch (addr) + { + case 0x00: return 0x23; /*Trident*/ + case 0x01: return 0x10; + + case 0x02: return 0x40; /*TGUI9440 (9682)*/ + case 0x03: return 0x94; + + case 0x04: return 0x03; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return tgui->linear_base >> 16; + case 0x13: return tgui->linear_base >> 24; + + case 0x30: return 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return 0x0C; + case 0x33: return 0x00; + } + return 0; +} + +void tgui_pci_write(int func, int addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + +// pclog("Trident PCI write %08X %02X\n", addr, val); + + switch (addr) + { + case 0x12: + tgui->linear_base = (tgui->linear_base & 0xff000000) | ((val & 0xe0) << 16); + tgui->linear_size = 2 << 20; + svga->crtc[0x21] = (svga->crtc[0x21] & ~0xf) | (val >> 4); + tgui_recalcmapping(tgui); + break; + case 0x13: + tgui->linear_base = (tgui->linear_base & 0xe00000) | (val << 24); + tgui->linear_size = 2 << 20; + svga->crtc[0x21] = (svga->crtc[0x21] & ~0xc0) | (val >> 6); + tgui_recalcmapping(tgui); + break; + } +} + +void *tgui9440_init() +{ + tgui_t *tgui = malloc(sizeof(tgui_t)); + memset(tgui, 0, sizeof(tgui_t)); + + tgui->vram_size = device_get_config_int("memory") << 20; + tgui->vram_mask = tgui->vram_size - 1; + + rom_init(&tgui->bios_rom, "roms/9440.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&tgui->svga, tgui, tgui->vram_size, + tgui_recalctimings, + tgui_in, tgui_out, + tgui_hwcursor_draw, + NULL); + + mem_mapping_add(&tgui->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &tgui->svga); + mem_mapping_add(&tgui->accel_mapping, 0xbc000, 0x4000, tgui_accel_read, tgui_accel_read_w, tgui_accel_read_l, tgui_accel_write, tgui_accel_write_w, tgui_accel_write_l, NULL, 0, tgui); + mem_mapping_disable(&tgui->accel_mapping); + + io_sethandler(0x03c0, 0x0020, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + io_sethandler(0x43c8, 0x0002, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + + pci_add(tgui_pci_read, tgui_pci_write, tgui); + + tgui->wake_fifo_thread = thread_create_event(); + tgui->fifo_not_full_event = thread_create_event(); + tgui->fifo_thread = thread_create(fifo_thread, tgui); + + return tgui; +} + +static int tgui9440_available() +{ + return rom_present("roms/9440.vbi"); +} + +void tgui_close(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_close(&tgui->svga); + + free(tgui); +} + +void tgui_speed_changed(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_recalctimings(&tgui->svga); +} + +void tgui_force_redraw(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + tgui->svga.fullchange = changeframecount; +} + +enum +{ + TGUI_BITBLT = 1 +}; + +enum +{ + TGUI_SRCCPU = 0, + + TGUI_SRCDISP = 0x04, /*Source is from display*/ + TGUI_PATMONO = 0x20, /*Pattern is monochrome and needs expansion*/ + TGUI_SRCMONO = 0x40, /*Source is monochrome from CPU and needs expansion*/ + TGUI_TRANSENA = 0x1000, /*Transparent (no draw when source == bg col)*/ + TGUI_TRANSREV = 0x2000, /*Reverse fg/bg for transparent*/ + TGUI_SOLIDFILL = 0x4000 /*Pattern all zero?*/ +}; + +#define READ(addr, dat) if (tgui->accel.bpp == 0) dat = svga->vram[addr & 0x1fffff]; \ + else dat = vram_w[addr & 0xfffff]; + +#define MIX() do \ + { \ + out = 0; \ + for (c=0;c<16;c++) \ + { \ + d=(dst_dat & (1<accel.rop & (1<accel.bpp == 0) \ + { \ + svga->vram[addr & 0x1fffff] = dat; \ + svga->changedvram[((addr) & 0x1fffff) >> 12] = changeframecount; \ + } \ + else \ + { \ + vram_w[addr & 0xfffff] = dat; \ + svga->changedvram[((addr) & 0xfffff) >> 11] = changeframecount; \ + } + +void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *priv); +void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *priv); + +void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) +{ + svga_t *svga = &tgui->svga; + int x, y; + int c, d; + uint16_t src_dat, dst_dat, pat_dat; + uint16_t out; + int xdir = (tgui->accel.flags & 0x200) ? -1 : 1; + int ydir = (tgui->accel.flags & 0x100) ? -1 : 1; + uint16_t trans_col = (tgui->accel.flags & TGUI_TRANSREV) ? tgui->accel.fg_col : tgui->accel.bg_col; + uint16_t *vram_w = (uint16_t *)svga->vram; + + if (tgui->accel.bpp == 0) + trans_col &= 0xff; + + if (count != -1 && !tgui->accel.x) + { + count -= tgui->accel.offset; + cpu_dat <<= tgui->accel.offset; + } + if (count == -1) + { + tgui->accel.x = tgui->accel.y = 0; + } + if (tgui->accel.flags & TGUI_SOLIDFILL) + { +// pclog("SOLIDFILL\n"); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.fg_col; + } + } + } + else if (tgui->accel.flags & TGUI_PATMONO) + { +// pclog("PATMONO\n"); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = (tgui->accel.pattern[y] & (1 << x)) ? tgui->accel.fg_col : tgui->accel.bg_col; + } + } + } + else + { + if (tgui->accel.bpp == 0) + { +// pclog("OTHER 8-bit\n"); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x + y*8]; + } + } + } + else + { +// pclog("OTHER 16-bit\n"); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x*2 + y*16] | (tgui->accel.pattern[x*2 + y*16 + 1] << 8); + } + } + } + } +/* for (y = 0; y < 8; y++) + { + if (count == -1) pclog("Pattern %i : %02X %02X %02X %02X %02X %02X %02X %02X\n", y, tgui->accel.tgui_pattern[y][0], tgui->accel.tgui_pattern[y][1], tgui->accel.tgui_pattern[y][2], tgui->accel.tgui_pattern[y][3], tgui->accel.tgui_pattern[y][4], tgui->accel.tgui_pattern[y][5], tgui->accel.tgui_pattern[y][6], tgui->accel.tgui_pattern[y][7]); + }*/ +// if (count == -1) pclog("Command %i %i %p\n", tgui->accel.command, TGUI_BITBLT, tgui); + switch (tgui->accel.command) + { + case TGUI_BITBLT: +// if (count == -1) pclog("BITBLT src %i,%i dst %i,%i size %i,%i flags %04X\n", tgui->accel.src_x, tgui->accel.src_y, tgui->accel.dst_x, tgui->accel.dst_y, tgui->accel.size_x, tgui->accel.size_y, tgui->accel.flags); + if (count == -1) + { + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_x + (tgui->accel.dst_y * tgui->accel.pitch); + tgui->accel.pat_x = tgui->accel.dst_x; + tgui->accel.pat_y = tgui->accel.dst_y; + } + + switch (tgui->accel.flags & (TGUI_SRCMONO|TGUI_SRCDISP)) + { + case TGUI_SRCCPU: + if (count == -1) + { +// pclog("Blit start TGUI_SRCCPU\n"); + if (svga->crtc[0x21] & 0x20) + mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l); + + if (tgui->accel.use_src) + return; + } + else + count >>= 3; +// pclog("TGUI_SRCCPU\n"); + while (count) + { + if (tgui->accel.bpp == 0) + { + src_dat = cpu_dat >> 24; + cpu_dat <<= 8; + } + else + { + src_dat = (cpu_dat >> 24) | ((cpu_dat >> 8) & 0xff00); + cpu_dat <<= 16; + count--; + } + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } + +// pclog(" %i,%i %02X %02X %02X %02X\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out); + + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + { + if (svga->crtc[0x21] & 0x20) + { +// pclog("Blit end\n"); + mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); + } + return; + } + if (tgui->accel.use_src) + return; + } + count--; + } + break; + + case TGUI_SRCMONO | TGUI_SRCCPU: + if (count == -1) + { +// pclog("Blit start TGUI_SRCMONO | TGUI_SRCCPU\n"); + if (svga->crtc[0x21] & 0x20) + mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l); + +// pclog(" %i\n", tgui->accel.command); + if (tgui->accel.use_src) + return; + } +// pclog("TGUI_SRCMONO | TGUI_SRCCPU\n"); + while (count) + { + src_dat = ((cpu_dat >> 31) ? tgui->accel.fg_col : tgui->accel.bg_col); + if (tgui->accel.bpp == 0) + src_dat &= 0xff; + + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } +// pclog(" %i,%i %02X %02X %02X %02X %i\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out, (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col)); + cpu_dat <<= 1; + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + { + if (svga->crtc[0x21] & 0x20) + { +// pclog("Blit end\n"); + mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); + } + return; + } + if (tgui->accel.use_src) + return; + } + count--; + } + break; + + default: + while (count) + { + READ(tgui->accel.src, src_dat); + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } +// pclog(" %i,%i %02X %02X %02X %02X\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out); + + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + return; + } + count--; + } + break; + } + break; + } +} + +static void tgui_accel_write_fifo(tgui_t *tgui, uint32_t addr, uint8_t val) +{ + switch (addr & 0xff) + { + case 0x22: + tgui->accel.ger22 = val; + tgui->accel.pitch = 512 << ((val >> 2) & 3); + tgui->accel.bpp = (val & 3) ? 1 : 0; + tgui->accel.pitch >>= tgui->accel.bpp; + break; + + case 0x24: /*Command*/ + tgui->accel.command = val; + tgui_accel_command(-1, 0, tgui); + break; + + case 0x27: /*ROP*/ + tgui->accel.rop = val; + tgui->accel.use_src = (val & 0x33) ^ ((val >> 2) & 0x33); +// pclog("Write ROP %02X %i\n", val, tgui->accel.use_src); + break; + + case 0x28: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff00) | val; + break; + case 0x29: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff) | (val << 8); + break; + + case 0x2b: + tgui->accel.offset = val & 7; + break; + + case 0x2c: /*Foreground colour*/ + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff00) | val; + break; + case 0x2d: /*Foreground colour*/ + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff) | (val << 8); + break; + + case 0x30: /*Background colour*/ + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff00) | val; + break; + case 0x31: /*Background colour*/ + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff) | (val << 8); + break; + + case 0x38: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff00) | val; + break; + case 0x39: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff) | (val << 8); + break; + case 0x3a: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff00) | val; + break; + case 0x3b: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff) | (val << 8); + break; + + case 0x3c: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff00) | val; + break; + case 0x3d: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff) | (val << 8); + break; + case 0x3e: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff00) | val; + break; + case 0x3f: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff) | (val << 8); + break; + + case 0x40: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff00) | val; + break; + case 0x41: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff) | (val << 8); + break; + case 0x42: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff00) | val; + break; + case 0x43: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff) | (val << 8); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + tgui->accel.pattern[addr & 0x7f] = val; + break; + } +} + +static void tgui_accel_write_fifo_fb_b(tgui_t *tgui, uint32_t addr, uint8_t val) +{ + tgui_accel_command(8, val << 24, tgui); +} +static void tgui_accel_write_fifo_fb_w(tgui_t *tgui, uint32_t addr, uint16_t val) +{ + tgui_accel_command(16, (((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)) << 16, tgui); +} +static void tgui_accel_write_fifo_fb_l(tgui_t *tgui, uint32_t addr, uint32_t val) +{ + tgui_accel_command(32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), tgui); +} + +static void fifo_thread(void *param) +{ + tgui_t *tgui = (tgui_t *)param; + + while (1) + { + thread_set_event(tgui->fifo_not_full_event); + thread_wait_event(tgui->wake_fifo_thread, -1); + thread_reset_event(tgui->wake_fifo_thread); + tgui->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + tgui_accel_write_fifo(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_BYTE: + tgui_accel_write_fifo_fb_b(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_WORD: + tgui_accel_write_fifo_fb_w(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_LONG: + tgui_accel_write_fifo_fb_l(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + tgui->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(tgui->fifo_not_full_event); + + end_time = timer_read(); + tgui->blitter_time += end_time - start_time; + } + tgui->blitter_busy = 0; + } +} + +static inline void wake_fifo_thread(tgui_t *tgui) +{ + thread_set_event(tgui->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void tgui_wait_fifo_idle(tgui_t *tgui) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(tgui); + thread_wait_event(tgui->fifo_not_full_event, 1); + } +} + +static void tgui_queue(tgui_t *tgui, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(tgui->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(tgui->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + tgui->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(tgui); +} + + +void tgui_accel_write(uint32_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_write : %08X %02X %04X(%08X):%08X %02X\n", addr, val, CS,cs,pc, opcode); + if ((addr & ~0xff) != 0xbff00) + return; + tgui_queue(tgui, addr, val, FIFO_WRITE_BYTE); +} + +void tgui_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_write_w %08X %04X\n", addr, val); + tgui_accel_write(addr, val, tgui); + tgui_accel_write(addr + 1, val >> 8, tgui); +} + +void tgui_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_write_l %08X %08X\n", addr, val); + tgui_accel_write(addr, val, tgui); + tgui_accel_write(addr + 1, val >> 8, tgui); + tgui_accel_write(addr + 2, val >> 16, tgui); + tgui_accel_write(addr + 3, val >> 24, tgui); +} + +uint8_t tgui_accel_read(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_read : %08X\n", addr); + if ((addr & ~0xff) != 0xbff00) + return 0xff; + if ((addr & 0xff) != 0x20) + tgui_wait_fifo_idle(tgui); + switch (addr & 0xff) + { + case 0x20: /*Status*/ + if (!FIFO_EMPTY) + return 1 << 5; + return 0; + + case 0x27: /*ROP*/ + return tgui->accel.rop; + + case 0x28: /*Flags*/ + return tgui->accel.flags & 0xff; + case 0x29: /*Flags*/ + return tgui->accel.flags >> 8; + + case 0x2b: + return tgui->accel.offset; + + case 0x2c: /*Background colour*/ + return tgui->accel.bg_col & 0xff; + case 0x2d: /*Background colour*/ + return tgui->accel.bg_col >> 8; + + case 0x30: /*Foreground colour*/ + return tgui->accel.fg_col & 0xff; + case 0x31: /*Foreground colour*/ + return tgui->accel.fg_col >> 8; + + case 0x38: /*Dest X*/ + return tgui->accel.dst_x & 0xff; + case 0x39: /*Dest X*/ + return tgui->accel.dst_x >> 8; + case 0x3a: /*Dest Y*/ + return tgui->accel.dst_y & 0xff; + case 0x3b: /*Dest Y*/ + return tgui->accel.dst_y >> 8; + + case 0x3c: /*Src X*/ + return tgui->accel.src_x & 0xff; + case 0x3d: /*Src X*/ + return tgui->accel.src_x >> 8; + case 0x3e: /*Src Y*/ + return tgui->accel.src_y & 0xff; + case 0x3f: /*Src Y*/ + return tgui->accel.src_y >> 8; + + case 0x40: /*Size X*/ + return tgui->accel.size_x & 0xff; + case 0x41: /*Size X*/ + return tgui->accel.size_x >> 8; + case 0x42: /*Size Y*/ + return tgui->accel.size_y & 0xff; + case 0x43: /*Size Y*/ + return tgui->accel.size_y >> 8; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return tgui->accel.pattern[addr & 0x7f]; + } + return 0xff; +} + +uint16_t tgui_accel_read_w(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_read_w %08X\n", addr); + return tgui_accel_read(addr, tgui) | (tgui_accel_read(addr + 1, tgui) << 8); +} + +uint32_t tgui_accel_read_l(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_read_l %08X\n", addr); + return tgui_accel_read_w(addr, tgui) | (tgui_accel_read_w(addr + 2, tgui) << 16); +} + +void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; +// pclog("tgui_accel_write_fb_b %08X %02X\n", addr, val); + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_BYTE); +} + +void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; +// pclog("tgui_accel_write_fb_w %08X %04X\n", addr, val); + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_WORD); +} + +void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; +// pclog("tgui_accel_write_fb_l %08X %08X\n", addr, val); + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_LONG); +} + +void tgui_add_status_info(char *s, int max_len, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - tgui->status_time; + tgui->status_time = new_time; + + svga_add_status_info(s, max_len, &tgui->svga); + + sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)tgui->blitter_time * 100.0) / timer_freq, ((double)tgui->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + tgui->blitter_time = 0; +} + +static device_config_t tgui9440_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +device_t tgui9440_device = +{ + "Trident TGUI 9440", + 0, + tgui9440_init, + tgui_close, + tgui9440_available, + tgui_speed_changed, + tgui_force_redraw, + tgui_add_status_info, + tgui9440_config +}; diff --git a/src/vid_tgui9440.h b/src/vid_tgui9440.h new file mode 100644 index 000000000..d5a09458e --- /dev/null +++ b/src/vid_tgui9440.h @@ -0,0 +1 @@ +extern device_t tgui9440_device; diff --git a/src/vid_tkd8001_ramdac.c b/src/vid_tkd8001_ramdac.c new file mode 100644 index 000000000..13f20e6e6 --- /dev/null +++ b/src/vid_tkd8001_ramdac.c @@ -0,0 +1,65 @@ +/*Trident TKD8001 RAMDAC emulation*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_tkd8001_ramdac.h" + +static int tkd8001_state=0; +static uint8_t tkd8001_ctrl; + +void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga) +{ +// pclog("OUT RAMDAC %04X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + ramdac->ctrl = val; + switch (val >> 5) + { + case 0: case 1: case 2: case 3: + svga->bpp = 8; + break; + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 24; + break; + case 7: + svga->bpp = 16; + break; + } + return; + } + // tkd8001_state = 0; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga) +{ +// pclog("IN RAMDAC %04X %04X:%04X\n",addr,CS,pc); + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + //tkd8001_state = 0; + return ramdac->ctrl; + } + ramdac->state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + return svga_in(addr, svga); +} diff --git a/src/vid_tkd8001_ramdac.h b/src/vid_tkd8001_ramdac.h new file mode 100644 index 000000000..b6db31b60 --- /dev/null +++ b/src/vid_tkd8001_ramdac.h @@ -0,0 +1,8 @@ +typedef struct tkd8001_ramdac_t +{ + int state; + uint8_t ctrl; +} tkd8001_ramdac_t; + +void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga); +uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga); diff --git a/src/vid_tvga.c b/src/vid_tvga.c new file mode 100644 index 000000000..174a132b7 --- /dev/null +++ b/src/vid_tvga.c @@ -0,0 +1,389 @@ +/*Trident TVGA (8900D) emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_tkd8001_ramdac.h" +#include "vid_tvga.h" + +typedef struct tvga_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t accel_mapping; + + svga_t svga; + tkd8001_ramdac_t ramdac; + + rom_t bios_rom; + + uint8_t tvga_3d8, tvga_3d9; + int oldmode; + uint8_t oldctrl1; + uint8_t oldctrl2, newctrl2; + + int vram_size; + uint32_t vram_mask; +} tvga_t; + +static uint8_t crtc_mask[0x40] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0xff, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xef, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void tvga_recalcbanking(tvga_t *tvga); +void tvga_out(uint16_t addr, uint8_t val, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + svga_t *svga = &tvga->svga; + + uint8_t old; + +// pclog("tvga_out : %04X %02X %04X:%04X %i\n", addr, val, CS,pc, svga->bpp); + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + switch (svga->seqaddr & 0xf) + { + case 0xB: + tvga->oldmode=1; + break; + case 0xC: + if (svga->seqregs[0xe] & 0x80) + svga->seqregs[0xc] = val; + break; + case 0xd: + if (tvga->oldmode) + tvga->oldctrl2 = val; + else + { + tvga->newctrl2 = val; + svga_recalctimings(svga); + } + break; + case 0xE: + if (tvga->oldmode) + tvga->oldctrl1 = val; + else + { + svga->seqregs[0xe] = val ^ 2; + tvga->tvga_3d8 = svga->seqregs[0xe] & 0xf; + tvga_recalcbanking(tvga); + } + return; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + tkd8001_ramdac_out(addr, val, &tvga->ramdac, svga); + return; + + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 0xE: + svga->gdcreg[0xe] = val ^ 2; + tvga->tvga_3d9 = svga->gdcreg[0xe] & 0xf; + tvga_recalcbanking(tvga); + break; + case 0xF: + svga->gdcreg[0xf] = val; + tvga_recalcbanking(tvga); + break; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; +// if (svga->crtcreg != 0xC && svga->crtcreg != 0xE && svga->crtcreg != 0xF) pclog("CRTC R%02X = %02X %04X:%04X\n", svga->crtcreg, val, CS, pc); + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + switch (svga->crtcreg) + { + case 0x1e: + svga->vrammask = (val & 0x80) ? tvga->vram_mask : 0x3ffff; + break; + } + return; + case 0x3D8: + if (svga->gdcreg[0xf] & 4) + { + tvga->tvga_3d8 = val; + tvga_recalcbanking(tvga); + } + return; + case 0x3D9: + if (svga->gdcreg[0xf] & 4) + { + tvga->tvga_3d9 = val; + tvga_recalcbanking(tvga); + } + return; + } + svga_out(addr, val, svga); +} + +uint8_t tvga_in(uint16_t addr, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + svga_t *svga = &tvga->svga; + +// if (addr != 0x3da) pclog("tvga_in : %04X %04X:%04X\n", addr, CS,pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 0xb) + { +// printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); + tvga->oldmode = 0; + return 0x33; /*TVGA8900D*/ + } + if ((svga->seqaddr & 0xf) == 0xc) + { +// printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); +// return 0x20; /*2 DRAM banks*/ + } + if ((svga->seqaddr & 0xf) == 0xd) + { + if (tvga->oldmode) return tvga->oldctrl2; + return tvga->newctrl2; + } + if ((svga->seqaddr & 0xf) == 0xe) + { + if (tvga->oldmode) + return tvga->oldctrl1; + } + break; + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return tkd8001_ramdac_in(addr, &tvga->ramdac, svga); + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x18 && svga->crtcreg < 0x1e) + return 0xff; + return svga->crtc[svga->crtcreg]; + case 0x3d8: + return tvga->tvga_3d8; + case 0x3d9: + return tvga->tvga_3d9; + } + return svga_in(addr, svga); +} + +static void tvga_recalcbanking(tvga_t *tvga) +{ + svga_t *svga = &tvga->svga; + + svga->write_bank = (tvga->tvga_3d8 & 0x1f) * 65536; + + if (svga->gdcreg[0xf] & 1) + svga->read_bank = (tvga->tvga_3d9 & 0x1f) * 65536; + else + svga->read_bank = svga->write_bank; + +// pclog("recalcbanking: write_bank=%08x read_bank=%08x GDC[E]=%02x GDC[F]=%02x SEQ[E]=%02x 3d8=%02x 3d9=%02x\n", svga->read_bank, svga->write_bank, svga->gdcreg[0xe], svga->gdcreg[0xf], svga->seqregs[0xe], tvga->tvga_3d8, tvga->tvga_3d9); +} + +void tvga_recalctimings(svga_t *svga) +{ + tvga_t *tvga = (tvga_t *)svga->p; + if (!svga->rowoffset) svga->rowoffset = 0x100; /*This is the only sensible way I can see this being handled, + given that TVGA8900D has no overflow bits. + Some sort of overflow is required for 320x200x24 and 1024x768x16*/ + if (svga->crtc[0x29] & 0x10) + svga->rowoffset += 0x100; + + if (svga->bpp == 24) + svga->hdisp = (svga->crtc[1] + 1) * 8; + + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; + + if (tvga->oldctrl2 & 0x10) + { + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; + } + if (svga->gdcreg[0xf] & 0x08) + { + svga->htotal *= 2; + svga->hdisp *= 2; + svga->hdisp_time *= 2; + } + + // svga->interlace = svga->crtc[0x1e] & 4; + if (svga->crtc[0x1e] & 4) + { + svga->rowoffset >>= 1; + svga->vtotal *= 2; + svga->dispend *= 2; + svga->vblankstart *= 2; + svga->vsyncstart *= 2; + svga->split *= 2; + } + + switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4)) + { + case 2: svga->clock = cpuclock/44900000.0; break; + case 3: svga->clock = cpuclock/36000000.0; break; + case 4: svga->clock = cpuclock/57272000.0; break; + case 5: svga->clock = cpuclock/65000000.0; break; + case 6: svga->clock = cpuclock/50350000.0; break; + case 7: svga->clock = cpuclock/40000000.0; break; + } + + if (tvga->oldctrl2 & 0x10) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + } + svga->lowres = 0; + } +} + +void *tvga8900d_init() +{ + tvga_t *tvga = malloc(sizeof(tvga_t)); + memset(tvga, 0, sizeof(tvga_t)); + + tvga->vram_size = device_get_config_int("memory") << 10; + tvga->vram_mask = tvga->vram_size - 1; + + rom_init(&tvga->bios_rom, "roms/TRIDENT.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&tvga->svga, tvga, tvga->vram_size, + tvga_recalctimings, + tvga_in, tvga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, tvga_in, NULL, NULL, tvga_out, NULL, NULL, tvga); + + return tvga; +} + +static int tvga8900d_available() +{ + return rom_present("roms/TRIDENT.BIN"); +} + +void tvga_close(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_close(&tvga->svga); + + free(tvga); +} + +void tvga_speed_changed(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_recalctimings(&tvga->svga); +} + +void tvga_force_redraw(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + tvga->svga.fullchange = changeframecount; +} + +void tvga_add_status_info(char *s, int max_len, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_add_status_info(s, max_len, &tvga->svga); +} + +static device_config_t tvga_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + /*Chip supports 2mb, but drivers are buggy*/ + { + .description = "" + } + }, + .default_int = 1024 + }, + { + .type = -1 + } +}; + +device_t tvga8900d_device = +{ + "Trident TVGA 8900D", + 0, + tvga8900d_init, + tvga_close, + tvga8900d_available, + tvga_speed_changed, + tvga_force_redraw, + tvga_add_status_info, + tvga_config +}; diff --git a/src/vid_tvga.h b/src/vid_tvga.h new file mode 100644 index 000000000..e49e21f05 --- /dev/null +++ b/src/vid_tvga.h @@ -0,0 +1 @@ +extern device_t tvga8900d_device; diff --git a/src/vid_unk_ramdac.c b/src/vid_unk_ramdac.c new file mode 100644 index 000000000..2b71647ae --- /dev/null +++ b/src/vid_unk_ramdac.c @@ -0,0 +1,64 @@ +/*It is unknown exactly what RAMDAC this is + It is possibly a Sierra 1502x + It's addressed by the TLIVESA1 driver for ET4000*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_unk_ramdac.h" + +void unk_ramdac_out(uint16_t addr, uint8_t val, unk_ramdac_t *ramdac, svga_t *svga) +{ + //pclog("OUT RAMDAC %04X %02X\n",addr,val); + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + ramdac->ctrl = val; + switch ((val&1)|((val&0xE0)>>4)) + { + case 0: case 1: case 2: case 3: + svga->bpp = 8; + break; + case 6: case 7: + svga->bpp = 15; + break; + case 8: case 9: case 0xA: case 0xB: + svga->bpp = 16; + break; + case 0xC: case 0xD: case 0xE: case 0xF: + svga->bpp = 24; + break; + } + return; + } + ramdac->state = 0; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t unk_ramdac_in(uint16_t addr, unk_ramdac_t *ramdac, svga_t *svga) +{ + //pclog("IN RAMDAC %04X\n",addr); + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + return ramdac->ctrl; + } + ramdac->state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + return svga_in(addr, svga); +} diff --git a/src/vid_unk_ramdac.h b/src/vid_unk_ramdac.h new file mode 100644 index 000000000..0f92848f2 --- /dev/null +++ b/src/vid_unk_ramdac.h @@ -0,0 +1,8 @@ +typedef struct unk_ramdac_t +{ + int state; + uint8_t ctrl; +} unk_ramdac_t; + +void unk_ramdac_out(uint16_t addr, uint8_t val, unk_ramdac_t *ramdac, svga_t *svga); +uint8_t unk_ramdac_in(uint16_t addr, unk_ramdac_t *ramdac, svga_t *svga); diff --git a/src/vid_vga.c b/src/vid_vga.c new file mode 100644 index 000000000..a800e9bc2 --- /dev/null +++ b/src/vid_vga.c @@ -0,0 +1,181 @@ +/*IBM VGA emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_vga.h" + +typedef struct vga_t +{ + svga_t svga; + + rom_t bios_rom; +} vga_t; + +void vga_out(uint16_t addr, uint8_t val, void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + uint8_t old; + +// pclog("vga_out : %04X %02X %04X:%04X %02X %i\n", addr, val, CS,pc, ram[0x489], ins); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 0x1f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t vga_in(uint16_t addr, void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("vga_in : %04X ", addr); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +void *vga_init() +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + rom_init(&vga->bios_rom, "roms/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} + +/*PS/1 uses a standard VGA controller, but with no option ROM*/ +void *ps1vga_init() +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} + +static int vga_available() +{ + return rom_present("roms/ibm_vga.bin"); +} + +void vga_close(void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_close(&vga->svga); + + free(vga); +} + +void vga_speed_changed(void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_recalctimings(&vga->svga); +} + +void vga_force_redraw(void *p) +{ + vga_t *vga = (vga_t *)p; + + vga->svga.fullchange = changeframecount; +} + +void vga_add_status_info(char *s, int max_len, void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_add_status_info(s, max_len, &vga->svga); +} + +device_t vga_device = +{ + "VGA", + 0, + vga_init, + vga_close, + vga_available, + vga_speed_changed, + vga_force_redraw, + vga_add_status_info +}; +device_t ps1vga_device = +{ + "PS/1 VGA", + 0, + ps1vga_init, + vga_close, + vga_available, + vga_speed_changed, + vga_force_redraw, + vga_add_status_info +}; diff --git a/src/vid_vga.h b/src/vid_vga.h new file mode 100644 index 000000000..9a45bef5d --- /dev/null +++ b/src/vid_vga.h @@ -0,0 +1,2 @@ +extern device_t vga_device; +extern device_t ps1vga_device; diff --git a/src/vid_voodoo.c b/src/vid_voodoo.c new file mode 100644 index 000000000..0acd6553c --- /dev/null +++ b/src/vid_voodoo.c @@ -0,0 +1,4565 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "pci.h" +#include "thread.h" +#include "timer.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_dither.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) +#define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x))) + +#define LOD_MAX 8 + +static int tris = 0; + +static uint64_t status_time = 0; +static uint64_t voodoo_time = 0; +static int voodoo_render_time[2] = {0, 0}; +static int voodoo_render_time_old[2] = {0, 0}; + +typedef union int_float +{ + uint32_t i; + float f; +} int_float; + +typedef struct rgb_t +{ + uint8_t b, g, r; + uint8_t pad; +} rgb_t; +typedef struct rgba8_t +{ + uint8_t b, g, r, a; +} rgba8_t; + +typedef union rgba_u +{ + struct + { + uint8_t b, g, r, a; + } rgba; + uint32_t u; +} rgba_u; + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (voodoo->fifo_write_idx - voodoo->fifo_read_idx) +#define FIFO_FULL ((voodoo->fifo_write_idx - voodoo->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (voodoo->fifo_read_idx == voodoo->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITEL_REG = (0x01 << 24), + FIFO_WRITEW_FB = (0x02 << 24), + FIFO_WRITEL_FB = (0x03 << 24), + FIFO_WRITEL_TEX = (0x04 << 24) +}; + +#define PARAM_SIZE 1024 +#define PARAM_MASK (PARAM_SIZE - 1) +#define PARAM_ENTRY_SIZE (1 << 31) + +#define PARAM_ENTRIES_1 (voodoo->params_write_idx - voodoo->params_read_idx[0]) +#define PARAM_ENTRIES_2 (voodoo->params_write_idx - voodoo->params_read_idx[1]) +#define PARAM_FULL_1 ((voodoo->params_write_idx - voodoo->params_read_idx[0]) >= PARAM_SIZE) +#define PARAM_FULL_2 ((voodoo->params_write_idx - voodoo->params_read_idx[1]) >= PARAM_SIZE) +#define PARAM_EMPTY_1 (voodoo->params_read_idx[0] == voodoo->params_write_idx) +#define PARAM_EMPTY_2 (voodoo->params_read_idx[1] == voodoo->params_write_idx) + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +static rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000]; + +typedef struct voodoo_params_t +{ + int command; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t startR, startG, startB, startZ, startA; + + int32_t dBdX, dGdX, dRdX, dAdX, dZdX; + + int32_t dBdY, dGdY, dRdY, dAdY, dZdY; + + int64_t startW, dWdX, dWdY; + + struct + { + int64_t startS, startT, startW, p1; + int64_t dSdX, dTdX, dWdX, p2; + int64_t dSdY, dTdY, dWdY, p3; + } tmu[1]; + + uint32_t color0, color1; + + uint32_t fbzMode; + uint32_t fbzColorPath; + + uint32_t fogMode; + rgb_t fogColor; + struct + { + uint8_t fog, dfog; + } fogTable[64]; + + uint32_t alphaMode; + + uint32_t zaColor; + + int chromaKey_r, chromaKey_g, chromaKey_b; + uint32_t chromaKey; + + uint32_t textureMode; + uint32_t tLOD; + + uint32_t texBaseAddr, texBaseAddr1, texBaseAddr2, texBaseAddr38; + + uint32_t tex_base[LOD_MAX+1]; + int tex_width; + int tex_w_mask[LOD_MAX+1]; + int tex_w_nmask[LOD_MAX+1]; + int tex_h_mask[LOD_MAX+1]; + int tex_shift[LOD_MAX+1]; + + uint32_t draw_offset, aux_offset; + + int tformat; + + int clipLeft, clipRight, clipLowY, clipHighY; + + int sign; + + uint32_t front_offset; + + uint32_t swapbufferCMD; + + rgba_u palette[256]; +} voodoo_params_t; + +typedef struct voodoo_t +{ + mem_mapping_t mapping; + + int pci_enable; + + uint8_t dac_data[8]; + int dac_reg, dac_reg_ff; + uint8_t dac_readdata; + uint16_t dac_pll_regs[16]; + + float pixel_clock; + int line_time; + + voodoo_params_t params; + + uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4; + + uint8_t initEnable; + + uint32_t lfbMode; + + uint32_t memBaseAddr; + + int_float fvertexAx, fvertexAy, fvertexBx, fvertexBy, fvertexCx, fvertexCy; + + uint32_t front_offset, back_offset; + + uint32_t fb_read_offset, fb_write_offset; + + int row_width; + + uint8_t *fb_mem, *tex_mem; + uint16_t *tex_mem_w; + + int rgb_sel; + + uint32_t trexInit1; + + int swap_count; + + int disp_buffer; + int timer_count; + + int line; + svga_t *svga; + + uint32_t backPorch; + uint32_t videoDimensions; + uint32_t hSync, vSync; + + int v_total, v_disp; + int h_disp; + int v_retrace; + + struct + { + uint32_t y[4], i[4], q[4]; + } nccTable[2]; + + rgba_u palette[256]; + + rgba_u ncc_lookup[2][256]; + int ncc_dirty; + + thread_t *fifo_thread; + thread_t *render_thread[2]; + event_t *wake_fifo_thread; + event_t *wake_main_thread; + event_t *fifo_not_full_event; + event_t *render_not_full_event[2]; + event_t *wake_render_thread[2]; + + int voodoo_busy; + int render_voodoo_busy[2]; + + int render_threads; + int odd_even_mask; + + int pixel_count[2], tri_count, frame_count; + int pixel_count_old[2]; + int wr_count, rd_count, tex_count; + + int retrace_count; + int swap_interval; + uint32_t swap_offset; + int swap_pending; + + int bilinear_enabled; + + int fb_size; + uint32_t fb_mask; + + int texture_size; + uint32_t texture_mask; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + int cmd_read, cmd_written; + + voodoo_params_t params_buffer[PARAM_SIZE]; + volatile int params_read_idx[2], params_write_idx; + + int flush; + + int scrfilter; + + uint32_t last_write_addr; + + uint32_t fbiPixelsIn; + uint32_t fbiChromaFail; + uint32_t fbiZFuncFail; + uint32_t fbiAFuncFail; + uint32_t fbiPixelsOut; + + rgb_t clutData[33]; + int clutData_dirty; + rgb_t clutData256[256]; + uint32_t video_16to32[0x10000]; + + uint8_t dirty_line[1024]; + int dirty_line_low, dirty_line_high; + + int fb_write_buffer, fb_draw_buffer; + + uint16_t thefilter[1024][1024]; // pixel filter, feeding from one or two + uint16_t thefilterg[1024][1024]; // for green + + /* the voodoo adds purple lines for some reason */ + uint16_t purpleline[1024]; + + int use_recompiler; + void *codegen_data; +} voodoo_t; + +enum +{ + SST_status = 0x000, + + SST_vertexAx = 0x008, + SST_vertexAy = 0x00c, + SST_vertexBx = 0x010, + SST_vertexBy = 0x014, + SST_vertexCx = 0x018, + SST_vertexCy = 0x01c, + + SST_startR = 0x0020, + SST_startG = 0x0024, + SST_startB = 0x0028, + SST_startZ = 0x002c, + SST_startA = 0x0030, + SST_startS = 0x0034, + SST_startT = 0x0038, + SST_startW = 0x003c, + + SST_dRdX = 0x0040, + SST_dGdX = 0x0044, + SST_dBdX = 0x0048, + SST_dZdX = 0x004c, + SST_dAdX = 0x0050, + SST_dSdX = 0x0054, + SST_dTdX = 0x0058, + SST_dWdX = 0x005c, + + SST_dRdY = 0x0060, + SST_dGdY = 0x0064, + SST_dBdY = 0x0068, + SST_dZdY = 0x006c, + SST_dAdY = 0x0070, + SST_dSdY = 0x0074, + SST_dTdY = 0x0078, + SST_dWdY = 0x007c, + + SST_triangleCMD = 0x0080, + + SST_fvertexAx = 0x088, + SST_fvertexAy = 0x08c, + SST_fvertexBx = 0x090, + SST_fvertexBy = 0x094, + SST_fvertexCx = 0x098, + SST_fvertexCy = 0x09c, + + SST_fstartR = 0x00a0, + SST_fstartG = 0x00a4, + SST_fstartB = 0x00a8, + SST_fstartZ = 0x00ac, + SST_fstartA = 0x00b0, + SST_fstartS = 0x00b4, + SST_fstartT = 0x00b8, + SST_fstartW = 0x00bc, + + SST_fdRdX = 0x00c0, + SST_fdGdX = 0x00c4, + SST_fdBdX = 0x00c8, + SST_fdZdX = 0x00cc, + SST_fdAdX = 0x00d0, + SST_fdSdX = 0x00d4, + SST_fdTdX = 0x00d8, + SST_fdWdX = 0x00dc, + + SST_fdRdY = 0x00e0, + SST_fdGdY = 0x00e4, + SST_fdBdY = 0x00e8, + SST_fdZdY = 0x00ec, + SST_fdAdY = 0x00f0, + SST_fdSdY = 0x00f4, + SST_fdTdY = 0x00f8, + SST_fdWdY = 0x00fc, + + SST_ftriangleCMD = 0x0100, + + SST_fbzColorPath = 0x104, + SST_fogMode = 0x108, + + SST_alphaMode = 0x10c, + SST_fbzMode = 0x110, + SST_lfbMode = 0x114, + + SST_clipLeftRight = 0x118, + SST_clipLowYHighY = 0x11c, + + SST_nopCMD = 0x120, + SST_fastfillCMD = 0x124, + SST_swapbufferCMD = 0x128, + + SST_fogColor = 0x12c, + SST_zaColor = 0x130, + SST_chromaKey = 0x134, + + SST_color0 = 0x144, + SST_color1 = 0x148, + + SST_fbiPixelsIn = 0x14c, + SST_fbiChromaFail = 0x150, + SST_fbiZFuncFail = 0x154, + SST_fbiAFuncFail = 0x158, + SST_fbiPixelsOut = 0x15c, + + SST_fogTable00 = 0x160, + SST_fogTable01 = 0x164, + SST_fogTable02 = 0x168, + SST_fogTable03 = 0x16c, + SST_fogTable04 = 0x170, + SST_fogTable05 = 0x174, + SST_fogTable06 = 0x178, + SST_fogTable07 = 0x17c, + SST_fogTable08 = 0x180, + SST_fogTable09 = 0x184, + SST_fogTable0a = 0x188, + SST_fogTable0b = 0x18c, + SST_fogTable0c = 0x190, + SST_fogTable0d = 0x194, + SST_fogTable0e = 0x198, + SST_fogTable0f = 0x19c, + SST_fogTable10 = 0x1a0, + SST_fogTable11 = 0x1a4, + SST_fogTable12 = 0x1a8, + SST_fogTable13 = 0x1ac, + SST_fogTable14 = 0x1b0, + SST_fogTable15 = 0x1b4, + SST_fogTable16 = 0x1b8, + SST_fogTable17 = 0x1bc, + SST_fogTable18 = 0x1c0, + SST_fogTable19 = 0x1c4, + SST_fogTable1a = 0x1c8, + SST_fogTable1b = 0x1cc, + SST_fogTable1c = 0x1d0, + SST_fogTable1d = 0x1d4, + SST_fogTable1e = 0x1d8, + SST_fogTable1f = 0x1dc, + + SST_fbiInit4 = 0x200, + + SST_backPorch = 0x208, + SST_videoDimensions = 0x20c, + SST_fbiInit0 = 0x210, + SST_fbiInit1 = 0x214, + SST_fbiInit2 = 0x218, + SST_fbiInit3 = 0x21c, + SST_hSync = 0x220, + SST_vSync = 0x224, + SST_clutData = 0x228, + SST_dacData = 0x22c, + + SST_textureMode = 0x300, + SST_tLOD = 0x304, + + SST_texBaseAddr = 0x30c, + SST_texBaseAddr1 = 0x310, + SST_texBaseAddr2 = 0x314, + SST_texBaseAddr38 = 0x318, + + SST_trexInit1 = 0x320, + + SST_nccTable0_Y0 = 0x324, + SST_nccTable0_Y1 = 0x328, + SST_nccTable0_Y2 = 0x32c, + SST_nccTable0_Y3 = 0x330, + SST_nccTable0_I0 = 0x334, + SST_nccTable0_I1 = 0x338, + SST_nccTable0_I2 = 0x33c, + SST_nccTable0_I3 = 0x340, + SST_nccTable0_Q0 = 0x344, + SST_nccTable0_Q1 = 0x348, + SST_nccTable0_Q2 = 0x34c, + SST_nccTable0_Q3 = 0x350, + + SST_nccTable1_Y0 = 0x354, + SST_nccTable1_Y1 = 0x358, + SST_nccTable1_Y2 = 0x35c, + SST_nccTable1_Y3 = 0x360, + SST_nccTable1_I0 = 0x364, + SST_nccTable1_I1 = 0x368, + SST_nccTable1_I2 = 0x36c, + SST_nccTable1_I3 = 0x370, + SST_nccTable1_Q0 = 0x374, + SST_nccTable1_Q1 = 0x378, + SST_nccTable1_Q2 = 0x37c, + SST_nccTable1_Q3 = 0x380, + + SST_remap_status = 0x000 | 0x400, + + SST_remap_vertexAx = 0x008 | 0x400, + SST_remap_vertexAy = 0x00c | 0x400, + SST_remap_vertexBx = 0x010 | 0x400, + SST_remap_vertexBy = 0x014 | 0x400, + SST_remap_vertexCx = 0x018 | 0x400, + SST_remap_vertexCy = 0x01c | 0x400, + + SST_remap_startR = 0x0020 | 0x400, + SST_remap_startG = 0x002c | 0x400, + SST_remap_startB = 0x0038 | 0x400, + SST_remap_startZ = 0x0044 | 0x400, + SST_remap_startA = 0x0050 | 0x400, + SST_remap_startS = 0x005c | 0x400, + SST_remap_startT = 0x0068 | 0x400, + SST_remap_startW = 0x0074 | 0x400, + + SST_remap_dRdX = 0x0024 | 0x400, + SST_remap_dGdX = 0x0030 | 0x400, + SST_remap_dBdX = 0x003c | 0x400, + SST_remap_dZdX = 0x0048 | 0x400, + SST_remap_dAdX = 0x0054 | 0x400, + SST_remap_dSdX = 0x0060 | 0x400, + SST_remap_dTdX = 0x006c | 0x400, + SST_remap_dWdX = 0x0078 | 0x400, + + SST_remap_dRdY = 0x0028 | 0x400, + SST_remap_dGdY = 0x0034 | 0x400, + SST_remap_dBdY = 0x0040 | 0x400, + SST_remap_dZdY = 0x004c | 0x400, + SST_remap_dAdY = 0x0058 | 0x400, + SST_remap_dSdY = 0x0064 | 0x400, + SST_remap_dTdY = 0x0070 | 0x400, + SST_remap_dWdY = 0x007c | 0x400, + + SST_remap_triangleCMD = 0x0080 | 0x400, + + SST_remap_fvertexAx = 0x088 | 0x400, + SST_remap_fvertexAy = 0x08c | 0x400, + SST_remap_fvertexBx = 0x090 | 0x400, + SST_remap_fvertexBy = 0x094 | 0x400, + SST_remap_fvertexCx = 0x098 | 0x400, + SST_remap_fvertexCy = 0x09c | 0x400, + + SST_remap_fstartR = 0x00a0 | 0x400, + SST_remap_fstartG = 0x00ac | 0x400, + SST_remap_fstartB = 0x00b8 | 0x400, + SST_remap_fstartZ = 0x00c4 | 0x400, + SST_remap_fstartA = 0x00d0 | 0x400, + SST_remap_fstartS = 0x00dc | 0x400, + SST_remap_fstartT = 0x00e8 | 0x400, + SST_remap_fstartW = 0x00f4 | 0x400, + + SST_remap_fdRdX = 0x00a4 | 0x400, + SST_remap_fdGdX = 0x00b0 | 0x400, + SST_remap_fdBdX = 0x00bc | 0x400, + SST_remap_fdZdX = 0x00c8 | 0x400, + SST_remap_fdAdX = 0x00d4 | 0x400, + SST_remap_fdSdX = 0x00e0 | 0x400, + SST_remap_fdTdX = 0x00ec | 0x400, + SST_remap_fdWdX = 0x00f8 | 0x400, + + SST_remap_fdRdY = 0x00a8 | 0x400, + SST_remap_fdGdY = 0x00b4 | 0x400, + SST_remap_fdBdY = 0x00c0 | 0x400, + SST_remap_fdZdY = 0x00cc | 0x400, + SST_remap_fdAdY = 0x00d8 | 0x400, + SST_remap_fdSdY = 0x00e4 | 0x400, + SST_remap_fdTdY = 0x00f0 | 0x400, + SST_remap_fdWdY = 0x00fc | 0x400, +}; + +enum +{ + LFB_WRITE_FRONT = 0x0000, + LFB_WRITE_BACK = 0x0010, + LFB_WRITE_MASK = 0x0030 +}; + +enum +{ + LFB_READ_FRONT = 0x0000, + LFB_READ_BACK = 0x0040, + LFB_READ_AUX = 0x0080, + LFB_READ_MASK = 0x00c0 +}; + +enum +{ + LFB_FORMAT_RGB565 = 0, + LFB_FORMAT_RGB555 = 1, + LFB_FORMAT_ARGB1555 = 2, + LFB_FORMAT_ARGB8888 = 5, + LFB_FORMAT_DEPTH = 15, + LFB_FORMAT_MASK = 15 +}; + +enum +{ + LFB_WRITE_COLOUR = 1, + LFB_WRITE_DEPTH = 2 +}; + +enum +{ + FBZ_CHROMAKEY = (1 << 1), + FBZ_W_BUFFER = (1 << 3), + FBZ_DEPTH_ENABLE = (1 << 4), + + FBZ_DITHER = (1 << 8), + FBZ_RGB_WMASK = (1 << 9), + FBZ_DEPTH_WMASK = (1 << 10), + FBZ_DITHER_2x2 = (1 << 11), + + FBZ_DRAW_FRONT = 0x0000, + FBZ_DRAW_BACK = 0x4000, + FBZ_DRAW_MASK = 0xc000, + + FBZ_DEPTH_BIAS = (1 << 16), + + FBZ_PARAM_ADJUST = (1 << 26) +}; + +enum +{ + TEX_RGB332 = 0x0, + TEX_Y4I2Q2 = 0x1, + TEX_A8 = 0x2, + TEX_I8 = 0x3, + TEX_AI8 = 0x4, + TEX_PAL8 = 0x5, + TEX_R5G6B5 = 0xa, + TEX_ARGB1555 = 0xb, + TEX_ARGB4444 = 0xc, + TEX_A8I8 = 0xd, + TEX_APAL88 = 0xe +}; + +enum +{ + TEXTUREMODE_NCC_SEL = (1 << 5), + TEXTUREMODE_TCLAMPS = (1 << 6), + TEXTUREMODE_TCLAMPT = (1 << 7) +}; + +enum +{ + FBIINIT0_VGA_PASS = 1 +}; + +enum +{ + FBIINIT3_REMAP = 1 +}; + +enum +{ + CC_LOCALSELECT_ITER_RGB = 0, + CC_LOCALSELECT_TEX = 1, + CC_LOCALSELECT_COLOR1 = 2, + CC_LOCALSELECT_LFB = 3 +}; + +enum +{ + CCA_LOCALSELECT_ITER_A = 0, + CCA_LOCALSELECT_COLOR0 = 1, + CCA_LOCALSELECT_ITER_Z = 2 +}; + +enum +{ + C_SEL_ITER_RGB = 0, + C_SEL_TEX = 1, + C_SEL_COLOR1 = 2, + C_SEL_LFB = 3 +}; + +enum +{ + A_SEL_ITER_A = 0, + A_SEL_TEX = 1, + A_SEL_COLOR1 = 2, + A_SEL_LFB = 3 +}; + +enum +{ + CC_MSELECT_ZERO = 0, + CC_MSELECT_CLOCAL = 1, + CC_MSELECT_AOTHER = 2, + CC_MSELECT_ALOCAL = 3, + CC_MSELECT_TEX = 4 +}; + +enum +{ + CCA_MSELECT_ZERO = 0, + CCA_MSELECT_ALOCAL = 1, + CCA_MSELECT_AOTHER = 2, + CCA_MSELECT_ALOCAL2 = 3, + CCA_MSELECT_TEX = 4 +}; + +enum +{ + CC_ADD_CLOCAL = 1, + CC_ADD_ALOCAL = 2 +}; + +enum +{ + CCA_ADD_CLOCAL = 1, + CCA_ADD_ALOCAL = 2 +}; + +enum +{ + AFUNC_AZERO = 0x0, + AFUNC_ASRC_ALPHA = 0x1, + AFUNC_A_COLOR = 0x2, + AFUNC_ADST_ALPHA = 0x3, + AFUNC_AONE = 0x4, + AFUNC_AOMSRC_ALPHA = 0x5, + AFUNC_AOM_COLOR = 0x6, + AFUNC_AOMDST_ALPHA = 0x7, + AFUNC_ASATURATE = 0xf +}; + +enum +{ + AFUNC_ACOLORBEFOREFOG = 0xf +}; + +enum +{ + AFUNC_NEVER = 0, + AFUNC_LESSTHAN = 1, + AFUNC_EQUAL = 2, + AFUNC_LESSTHANEQUAL = 3, + AFUNC_GREATERTHAN = 4, + AFUNC_NOTEQUAL = 5, + AFUNC_GREATERTHANEQUAL = 6, + AFUNC_ALWAYS = 7 +}; + +enum +{ + DEPTHOP_NEVER = 0, + DEPTHOP_LESSTHAN = 1, + DEPTHOP_EQUAL = 2, + DEPTHOP_LESSTHANEQUAL = 3, + DEPTHOP_GREATERTHAN = 4, + DEPTHOP_NOTEQUAL = 5, + DEPTHOP_GREATERTHANEQUAL = 6, + DEPTHOP_ALWAYS = 7 +}; + +enum +{ + FOG_ENABLE = 0x01, + FOG_ADD = 0x02, + FOG_MULT = 0x04, + FOG_ALPHA = 0x08, + FOG_Z = 0x10, + FOG_CONSTANT = 0x20 +}; + +enum +{ + LOD_S_IS_WIDER = (1 << 20) +}; +enum +{ + CMD_INVALID = 0, + CMD_DRAWTRIANGLE, + CMD_FASTFILL, + CMD_SWAPBUF +}; + +enum +{ + FBZCP_TEXTURE_ENABLED = (1 << 27) +}; + +static void voodoo_update_ncc(voodoo_t *voodoo) +{ + int tbl; + + for (tbl = 0; tbl < 2; tbl++) + { + int col; + + for (col = 0; col < 256; col++) + { + int y = (col >> 4), i = (col >> 2) & 3, q = col & 3; + int _y = (col >> 4), _i = (col >> 2) & 3, _q = col & 3; + int i_r, i_g, i_b; + int q_r, q_g, q_b; + int r, g, b; + + y = (voodoo->nccTable[tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff; + + i_r = (voodoo->nccTable[tbl].i[i] >> 18) & 0x1ff; + if (i_r & 0x100) + i_r |= 0xfffffe00; + i_g = (voodoo->nccTable[tbl].i[i] >> 9) & 0x1ff; + if (i_g & 0x100) + i_g |= 0xfffffe00; + i_b = voodoo->nccTable[tbl].i[i] & 0x1ff; + if (i_b & 0x100) + i_b |= 0xfffffe00; + + q_r = (voodoo->nccTable[tbl].q[q] >> 18) & 0x1ff; + if (q_r & 0x100) + q_r |= 0xfffffe00; + q_g = (voodoo->nccTable[tbl].q[q] >> 9) & 0x1ff; + if (q_g & 0x100) + q_g |= 0xfffffe00; + q_b = voodoo->nccTable[tbl].q[q] & 0x1ff; + if (q_b & 0x100) + q_b |= 0xfffffe00; + + voodoo->ncc_lookup[tbl][col].rgba.r = CLAMP(y + i_r + q_r); + voodoo->ncc_lookup[tbl][col].rgba.g = CLAMP(y + i_g + q_g); + voodoo->ncc_lookup[tbl][col].rgba.b = CLAMP(y + i_b + q_b); + voodoo->ncc_lookup[tbl][col].rgba.a = 0xff; + } + } +} + +static void voodoo_recalc(voodoo_t *voodoo) +{ + uint32_t buffer_offset = ((voodoo->fbiInit2 >> 11) & 511) * 4096; + + if (voodoo->disp_buffer) + { + voodoo->back_offset = 0; + voodoo->params.front_offset = buffer_offset; + } + else + { + voodoo->params.front_offset = 0; + voodoo->back_offset = buffer_offset; + } + voodoo->params.aux_offset = buffer_offset * 2; + + switch (voodoo->lfbMode & LFB_WRITE_MASK) + { + case LFB_WRITE_FRONT: + voodoo->fb_write_offset = voodoo->params.front_offset; + voodoo->fb_write_buffer = voodoo->disp_buffer ? 1 : 0; + break; + case LFB_WRITE_BACK: + voodoo->fb_write_offset = voodoo->back_offset; + voodoo->fb_write_buffer = voodoo->disp_buffer ? 0 : 1; + break; + + default: + /*BreakNeck sets invalid LFB write buffer select*/ + voodoo->fb_write_offset = voodoo->params.front_offset; + break; + } + + switch (voodoo->lfbMode & LFB_READ_MASK) + { + case LFB_READ_FRONT: + voodoo->fb_read_offset = voodoo->params.front_offset; + break; + case LFB_READ_BACK: + voodoo->fb_read_offset = voodoo->back_offset; + break; + case LFB_READ_AUX: + voodoo->fb_read_offset = voodoo->params.aux_offset; + break; + + default: + fatal("voodoo_recalc : unknown lfb source\n"); + } + + switch (voodoo->params.fbzMode & FBZ_DRAW_MASK) + { + case FBZ_DRAW_FRONT: + voodoo->params.draw_offset = voodoo->params.front_offset; + voodoo->fb_draw_buffer = voodoo->disp_buffer ? 1 : 0; + break; + case FBZ_DRAW_BACK: + voodoo->params.draw_offset = voodoo->back_offset; + voodoo->fb_draw_buffer = voodoo->disp_buffer ? 0 : 1; + break; + + default: + fatal("voodoo_recalc : unknown draw buffer\n"); + } + + voodoo->row_width = ((voodoo->fbiInit1 >> 4) & 15) * 64 * 2; +// pclog("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X draw_offset %08x\n", voodoo->params.front_offset, voodoo->back_offset, voodoo->params.aux_offset, voodoo->params.draw_offset); +// pclog(" fb_read_offset %08X fb_write_offset %08X row_width %i %08x %08x\n", voodoo->fb_read_offset, voodoo->fb_write_offset, voodoo->row_width, voodoo->lfbMode, voodoo->params.fbzMode); +} + +static void voodoo_recalc_tex(voodoo_t *voodoo) +{ + int aspect = (voodoo->params.tLOD >> 21) & 3; + int width = 256, height = 256; + int shift = 8; + int lod; + int lod_min = (voodoo->params.tLOD >> 2) & 15; + int lod_max = (voodoo->params.tLOD >> 8) & 15; + uint32_t base = voodoo->params.texBaseAddr; + + if (voodoo->params.tLOD & LOD_S_IS_WIDER) + height >>= aspect; + else + { + width >>= aspect; + shift -= aspect; + } + + for (lod = 0; lod <= LOD_MAX; lod++) + { + if (!width) + width = 1; + if (!height) + height = 1; + if (shift < 0) + shift = 0; + voodoo->params.tex_base[lod] = base; + voodoo->params.tex_w_mask[lod] = width - 1; + voodoo->params.tex_w_nmask[lod] = ~(width - 1); + voodoo->params.tex_h_mask[lod] = height - 1; + voodoo->params.tex_shift[lod] = shift; +// pclog("LOD%i base=%08x %i-%i %i,%i wm=%02x hm=%02x sh=%i\n", lod, base, lod_min, lod_max, width, height, voodoo->params.tex_w_mask[lod], voodoo->params.tex_h_mask[lod], voodoo->params.tex_shift[lod]); + + if (voodoo->params.tformat & 8) + base += width * height * 2; + else + base += width * height; + + width >>= 1; + height >>= 1; + shift--; + } + + voodoo->params.tex_width = width; +} + +typedef struct voodoo_state_t +{ + int xstart, xend, xdir; + uint32_t base_r, base_g, base_b, base_a, base_z; + struct + { + int64_t base_s, base_t, base_w; + int lod; + } tmu[1]; + int64_t base_w; + int lod; + int lod_min, lod_max; + int dx1, dx2; + int y, yend, ydir; + int32_t dxAB, dxAC, dxBC; + int tex_b, tex_g, tex_r, tex_a; + int tex_s, tex_t; + int clamp_s, clamp_t; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint8_t *tex[LOD_MAX+1]; + uint16_t *tex_w[LOD_MAX+1]; + int tformat; + + rgba_u *palette; + + int *tex_w_mask; + int *tex_h_mask; + int *tex_shift; + + uint16_t *fb_mem, *aux_mem; + + int32_t ib, ig, ir, ia; + int32_t z; + + int32_t new_depth; + + int64_t tmu0_s, tmu0_t; + int64_t tmu0_w; + int64_t w; + + int pixel_count; + int x, x2; + + uint32_t w_depth; + + float log_temp; + uint32_t ebp_store; +} voodoo_state_t; + +static int voodoo_output = 0; + +static uint8_t logtable[256] = +{ + 0x00,0x01,0x02,0x04,0x05,0x07,0x08,0x09,0x0b,0x0c,0x0e,0x0f,0x10,0x12,0x13,0x15, + 0x16,0x17,0x19,0x1a,0x1b,0x1d,0x1e,0x1f,0x21,0x22,0x23,0x25,0x26,0x27,0x28,0x2a, + 0x2b,0x2c,0x2e,0x2f,0x30,0x31,0x33,0x34,0x35,0x36,0x38,0x39,0x3a,0x3b,0x3d,0x3e, + 0x3f,0x40,0x41,0x43,0x44,0x45,0x46,0x47,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x50,0x51, + 0x52,0x53,0x54,0x55,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x60,0x61,0x62,0x63, + 0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, + 0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x83,0x84,0x85, + 0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94, + 0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa2,0xa3, + 0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xad,0xae,0xaf,0xb0,0xb1,0xb2, + 0xb3,0xb4,0xb5,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbc,0xbd,0xbe,0xbf,0xc0, + 0xc1,0xc2,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xcd, + 0xce,0xcf,0xd0,0xd1,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd6,0xd7,0xd8,0xd9,0xda,0xda, + 0xdb,0xdc,0xdd,0xde,0xde,0xdf,0xe0,0xe1,0xe1,0xe2,0xe3,0xe4,0xe5,0xe5,0xe6,0xe7, + 0xe8,0xe8,0xe9,0xea,0xeb,0xeb,0xec,0xed,0xee,0xef,0xef,0xf0,0xf1,0xf2,0xf2,0xf3, + 0xf4,0xf5,0xf5,0xf6,0xf7,0xf7,0xf8,0xf9,0xfa,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff +}; + +static inline int fastlog(uint64_t val) +{ + uint64_t oldval = val; + int exp = 63; + int frac; + + if (!val || val & (1ULL << 63)) + return 0x80000000; + + if (!(val & 0xffffffff00000000)) + { + exp -= 32; + val <<= 32; + } + if (!(val & 0xffff000000000000)) + { + exp -= 16; + val <<= 16; + } + if (!(val & 0xff00000000000000)) + { + exp -= 8; + val <<= 8; + } + if (!(val & 0xf000000000000000)) + { + exp -= 4; + val <<= 4; + } + if (!(val & 0xc000000000000000)) + { + exp -= 2; + val <<= 2; + } + if (!(val & 0x8000000000000000)) + { + exp -= 1; + val <<= 1; + } + + if (exp >= 8) + frac = (oldval >> (exp - 8)) & 0xff; + else + frac = (oldval << (8 - exp)) & 0xff; + + return (exp << 8) | logtable[frac]; +} + +static inline int fls(uint16_t val) +{ + int num = 0; + +//pclog("fls(%04x) = ", val); + if (!(val & 0xff00)) + { + num += 8; + val <<= 8; + } + if (!(val & 0xf000)) + { + num += 4; + val <<= 4; + } + if (!(val & 0xc000)) + { + num += 2; + val <<= 2; + } + if (!(val & 0x8000)) + { + num += 1; + val <<= 1; + } +//pclog("%i %04x\n", num, val); + return num; +} + +typedef struct voodoo_texture_state_t +{ + int s, t; + int w_mask, h_mask; + int tex_shift; +} voodoo_texture_state_t; + +static inline void tex_read(voodoo_state_t *state, voodoo_texture_state_t *texture_state) +{ + uint16_t dat; + + if (texture_state->s & ~texture_state->w_mask) + { + if (state->clamp_s) + { + if (texture_state->s < 0) + texture_state->s = 0; + if (texture_state->s > texture_state->w_mask) + texture_state->s = texture_state->w_mask; + } + else + texture_state->s &= texture_state->w_mask; + } + if (texture_state->t & ~texture_state->h_mask) + { + if (state->clamp_t) + { + if (texture_state->t < 0) + texture_state->t = 0; + if (texture_state->t > texture_state->h_mask) + texture_state->t = texture_state->h_mask; + } + else + texture_state->t &= texture_state->h_mask; + } + + if (state->tformat & 8) + dat = state->tex_w[state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; + else + dat = state->tex[state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; + + switch (state->tformat) + { + case TEX_RGB332: + state->tex_r = rgb332[dat].r; + state->tex_g = rgb332[dat].g; + state->tex_b = rgb332[dat].b; + state->tex_a = 0xff; + break; + + case TEX_Y4I2Q2: + state->tex_r = state->palette[dat].rgba.r; + state->tex_g = state->palette[dat].rgba.g; + state->tex_b = state->palette[dat].rgba.b; + state->tex_a = 0xff; + break; + + case TEX_A8: + state->tex_r = state->tex_g = state->tex_b = state->tex_a = dat & 0xff; + break; + + case TEX_I8: + state->tex_r = state->tex_g = state->tex_b = dat & 0xff; + state->tex_a = 0xff; + break; + + case TEX_AI8: + state->tex_r = state->tex_g = state->tex_b = (dat & 0x0f) | ((dat << 4) & 0xf0); + state->tex_a = (dat & 0xf0) | ((dat >> 4) & 0x0f); + break; + + case TEX_PAL8: + state->tex_r = state->palette[dat].rgba.r; + state->tex_g = state->palette[dat].rgba.g; + state->tex_b = state->palette[dat].rgba.b; + state->tex_a = 0xff; + break; + + case TEX_R5G6B5: + state->tex_r = rgb565[dat].r; + state->tex_g = rgb565[dat].g; + state->tex_b = rgb565[dat].b; + state->tex_a = 0xff; + break; + + case TEX_ARGB1555: + state->tex_r = argb1555[dat].r; + state->tex_g = argb1555[dat].g; + state->tex_b = argb1555[dat].b; + state->tex_a = argb1555[dat].a; + break; + + case TEX_ARGB4444: + state->tex_r = argb4444[dat].r; + state->tex_g = argb4444[dat].g; + state->tex_b = argb4444[dat].b; + state->tex_a = argb4444[dat].a; + break; + + case TEX_A8I8: + state->tex_r = state->tex_g = state->tex_b = dat & 0xff; + state->tex_a = dat >> 8; + break; + + case TEX_APAL88: + state->tex_r = state->palette[dat & 0xff].rgba.r; + state->tex_g = state->palette[dat & 0xff].rgba.g; + state->tex_b = state->palette[dat & 0xff].rgba.b; + state->tex_a = dat >> 8; + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } +} + +#define LOW4(x) ((x & 0x0f) | ((x & 0x0f) << 4)) +#define HIGH4(x) ((x & 0xf0) | ((x & 0xf0) >> 4)) + +static inline void tex_read_4(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int s, int t, int *d) +{ + uint16_t dat[4]; + + if (((s | (s + 1)) & ~texture_state->w_mask) || ((t | (t + 1)) & ~texture_state->h_mask)) + { + int c; + for (c = 0; c < 4; c++) + { + int _s = s + (c & 1); + int _t = t + ((c & 2) >> 1); + + if (_s & ~texture_state->w_mask) + { + if (state->clamp_s) + { + if (_s < 0) + _s = 0; + if (_s > texture_state->w_mask) + _s = texture_state->w_mask; + } + else + _s &= texture_state->w_mask; + } + if (_t & ~texture_state->h_mask) + { + if (state->clamp_t) + { + if (_t < 0) + _t = 0; + if (_t > texture_state->h_mask) + _t = texture_state->h_mask; + } + else + _t &= texture_state->h_mask; + } + if (state->tformat & 8) + dat[c] = state->tex_w[state->lod][_s + (_t << texture_state->tex_shift)]; + else + dat[c] = state->tex[state->lod][_s + (_t << texture_state->tex_shift)]; + } + } + else + { + if (state->tformat & 8) + { + dat[0] = state->tex_w[state->lod][s + (t << texture_state->tex_shift)]; + dat[1] = state->tex_w[state->lod][s + 1 + (t << texture_state->tex_shift)]; + dat[2] = state->tex_w[state->lod][s + ((t + 1) << texture_state->tex_shift)]; + dat[3] = state->tex_w[state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; + } + else + { + dat[0] = state->tex[state->lod][s + (t << texture_state->tex_shift)]; + dat[1] = state->tex[state->lod][s + 1 + (t << texture_state->tex_shift)]; + dat[2] = state->tex[state->lod][s + ((t + 1) << texture_state->tex_shift)]; + dat[3] = state->tex[state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; + } + } + + switch (state->tformat) + { + case TEX_RGB332: + state->tex_r = (rgb332[dat[0]].r * d[0] + rgb332[dat[1]].r * d[1] + rgb332[dat[2]].r * d[2] + rgb332[dat[3]].r * d[3]) >> 8; + state->tex_g = (rgb332[dat[0]].g * d[0] + rgb332[dat[1]].g * d[1] + rgb332[dat[2]].g * d[2] + rgb332[dat[3]].g * d[3]) >> 8; + state->tex_b = (rgb332[dat[0]].b * d[0] + rgb332[dat[1]].b * d[1] + rgb332[dat[2]].b * d[2] + rgb332[dat[3]].b * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_Y4I2Q2: + state->tex_r = (state->palette[dat[0]].rgba.r * d[0] + state->palette[dat[1]].rgba.r * d[1] + state->palette[dat[2]].rgba.r * d[2] + state->palette[dat[3]].rgba.r * d[3]) >> 8; + state->tex_g = (state->palette[dat[0]].rgba.g * d[0] + state->palette[dat[1]].rgba.g * d[1] + state->palette[dat[2]].rgba.g * d[2] + state->palette[dat[3]].rgba.g * d[3]) >> 8; + state->tex_b = (state->palette[dat[0]].rgba.b * d[0] + state->palette[dat[1]].rgba.b * d[1] + state->palette[dat[2]].rgba.b * d[2] + state->palette[dat[3]].rgba.b * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_A8: + state->tex_r = state->tex_g = state->tex_b = state->tex_a = (dat[0] * d[0] + dat[1] * d[1] + dat[2] * d[2] + dat[3] * d[3]) >> 8; + break; + + case TEX_I8: + state->tex_r = state->tex_g = state->tex_b = (dat[0] * d[0] + dat[1] * d[1] + dat[2] * d[2] + dat[3] * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_AI8: + state->tex_r = state->tex_g = state->tex_b = (LOW4(dat[0]) * d[0] + LOW4(dat[1]) * d[1] + LOW4(dat[2]) * d[2] + LOW4(dat[3]) * d[3]) >> 8; + state->tex_a = (HIGH4(dat[0]) * d[0] + HIGH4(dat[1]) * d[1] + HIGH4(dat[2]) * d[2] + HIGH4(dat[3]) * d[3]) >> 8; + break; + + case TEX_PAL8: + state->tex_r = (state->palette[dat[0]].rgba.r * d[0] + state->palette[dat[1]].rgba.r * d[1] + state->palette[dat[2]].rgba.r * d[2] + state->palette[dat[3]].rgba.r * d[3]) >> 8; + state->tex_g = (state->palette[dat[0]].rgba.g * d[0] + state->palette[dat[1]].rgba.g * d[1] + state->palette[dat[2]].rgba.g * d[2] + state->palette[dat[3]].rgba.g * d[3]) >> 8; + state->tex_b = (state->palette[dat[0]].rgba.b * d[0] + state->palette[dat[1]].rgba.b * d[1] + state->palette[dat[2]].rgba.b * d[2] + state->palette[dat[3]].rgba.b * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_R5G6B5: + state->tex_r = (rgb565[dat[0]].r * d[0] + rgb565[dat[1]].r * d[1] + rgb565[dat[2]].r * d[2] + rgb565[dat[3]].r * d[3]) >> 8; + state->tex_g = (rgb565[dat[0]].g * d[0] + rgb565[dat[1]].g * d[1] + rgb565[dat[2]].g * d[2] + rgb565[dat[3]].g * d[3]) >> 8; + state->tex_b = (rgb565[dat[0]].b * d[0] + rgb565[dat[1]].b * d[1] + rgb565[dat[2]].b * d[2] + rgb565[dat[3]].b * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_ARGB1555: + state->tex_r = (argb1555[dat[0]].r * d[0] + argb1555[dat[1]].r * d[1] + argb1555[dat[2]].r * d[2] + argb1555[dat[3]].r * d[3]) >> 8; + state->tex_g = (argb1555[dat[0]].g * d[0] + argb1555[dat[1]].g * d[1] + argb1555[dat[2]].g * d[2] + argb1555[dat[3]].g * d[3]) >> 8; + state->tex_b = (argb1555[dat[0]].b * d[0] + argb1555[dat[1]].b * d[1] + argb1555[dat[2]].b * d[2] + argb1555[dat[3]].b * d[3]) >> 8; + state->tex_a = (argb1555[dat[0]].a * d[0] + argb1555[dat[1]].a * d[1] + argb1555[dat[2]].a * d[2] + argb1555[dat[3]].a * d[3]) >> 8; + break; + + case TEX_ARGB4444: + state->tex_r = (argb4444[dat[0]].r * d[0] + argb4444[dat[1]].r * d[1] + argb4444[dat[2]].r * d[2] + argb4444[dat[3]].r * d[3]) >> 8; + state->tex_g = (argb4444[dat[0]].g * d[0] + argb4444[dat[1]].g * d[1] + argb4444[dat[2]].g * d[2] + argb4444[dat[3]].g * d[3]) >> 8; + state->tex_b = (argb4444[dat[0]].b * d[0] + argb4444[dat[1]].b * d[1] + argb4444[dat[2]].b * d[2] + argb4444[dat[3]].b * d[3]) >> 8; + state->tex_a = (argb4444[dat[0]].a * d[0] + argb4444[dat[1]].a * d[1] + argb4444[dat[2]].a * d[2] + argb4444[dat[3]].a * d[3]) >> 8; + break; + + case TEX_A8I8: + state->tex_r = state->tex_g = state->tex_b = ((dat[0] & 0xff) * d[0] + (dat[1] & 0xff) * d[1] + (dat[2] & 0xff) * d[2] + (dat[3] & 0xff) * d[3]) >> 8; + state->tex_a = ((dat[0] >> 8) * d[0] + (dat[1] >> 8) * d[1] + (dat[2] >> 8) * d[2] + (dat[3] >> 8) * d[3]) >> 8; + break; + + case TEX_APAL88: + state->tex_r = (state->palette[dat[0] & 0xff].rgba.r * d[0] + state->palette[dat[1] & 0xff].rgba.r * d[1] + state->palette[dat[2] & 0xff].rgba.r * d[2] + state->palette[dat[3] & 0xff].rgba.r * d[3]) >> 8; + state->tex_g = (state->palette[dat[0] & 0xff].rgba.g * d[0] + state->palette[dat[1] & 0xff].rgba.g * d[1] + state->palette[dat[2] & 0xff].rgba.g * d[2] + state->palette[dat[3] & 0xff].rgba.g * d[3]) >> 8; + state->tex_b = (state->palette[dat[0] & 0xff].rgba.b * d[0] + state->palette[dat[1] & 0xff].rgba.b * d[1] + state->palette[dat[2] & 0xff].rgba.b * d[2] + state->palette[dat[3] & 0xff].rgba.b * d[3]) >> 8; + state->tex_a = ((dat[0] >> 8) * d[0] + (dat[1] >> 8) * d[1] + (dat[2] >> 8) * d[2] + (dat[3] >> 8) * d[3]) >> 8; + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } +} + +static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state) +{ + rgba_u tex_samples[4]; + voodoo_texture_state_t texture_state; + int d[4]; + int s, t; + + texture_state.w_mask = state->tex_w_mask[state->lod]; + texture_state.h_mask = state->tex_h_mask[state->lod]; + texture_state.tex_shift = state->tex_shift[state->lod]; + + if (voodoo->bilinear_enabled && params->textureMode & 6) + { + int _ds, dt; + + state->tex_s -= 1 << (3+state->lod); + state->tex_t -= 1 << (3+state->lod); + + s = state->tex_s >> state->lod; + t = state->tex_t >> state->lod; + + _ds = s & 0xf; + dt = t & 0xf; + + s >>= 4; + t >>= 4; + +//if (x == 80) +//if (voodoo_output) +// pclog("s=%08x t=%08x _ds=%02x _dt=%02x\n", s, t, _ds, dt); + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + +// texture_state.s = s; +// texture_state.t = t; + tex_read_4(state, &texture_state, s, t, d); + + +/* state->tex_r = (tex_samples[0].rgba.r * d[0] + tex_samples[1].rgba.r * d[1] + tex_samples[2].rgba.r * d[2] + tex_samples[3].rgba.r * d[3]) >> 8; + state->tex_g = (tex_samples[0].rgba.g * d[0] + tex_samples[1].rgba.g * d[1] + tex_samples[2].rgba.g * d[2] + tex_samples[3].rgba.g * d[3]) >> 8; + state->tex_b = (tex_samples[0].rgba.b * d[0] + tex_samples[1].rgba.b * d[1] + tex_samples[2].rgba.b * d[2] + tex_samples[3].rgba.b * d[3]) >> 8; + state->tex_a = (tex_samples[0].rgba.a * d[0] + tex_samples[1].rgba.a * d[1] + tex_samples[2].rgba.a * d[2] + tex_samples[3].rgba.a * d[3]) >> 8;*/ +/* state->tex_r = tex_samples[0].r; + state->tex_g = tex_samples[0].g; + state->tex_b = tex_samples[0].b; + state->tex_a = tex_samples[0].a;*/ + } + else + { + // rgba_t tex_samples; + // voodoo_texture_state_t texture_state; +// int s = state->tex_s >> (18+state->lod); +// int t = state->tex_t >> (18+state->lod); + // int s, t; + +// state->tex_s -= 1 << (17+state->lod); +// state->tex_t -= 1 << (17+state->lod); + + s = state->tex_s >> (4+state->lod); + t = state->tex_t >> (4+state->lod); + + texture_state.s = s; + texture_state.t = t; + tex_read(state, &texture_state); + +/* state->tex_r = tex_samples[0].rgba.r; + state->tex_g = tex_samples[0].rgba.g; + state->tex_b = tex_samples[0].rgba.b; + state->tex_a = tex_samples[0].rgba.a;*/ + } +} + + +#define DEPTH_TEST() \ + do \ + { \ + switch (depth_op) \ + { \ + case DEPTHOP_NEVER: \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + case DEPTHOP_LESSTHAN: \ + if (!(new_depth < old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_EQUAL: \ + if (!(new_depth == old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_LESSTHANEQUAL: \ + if (!(new_depth <= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHAN: \ + if (!(new_depth > old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_NOTEQUAL: \ + if (!(new_depth != old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHANEQUAL: \ + if (!(new_depth >= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_ALWAYS: \ + break; \ + } \ + } while (0) + +#define APPLY_FOG(src_r, src_g, src_b, z, ia) \ + do \ + { \ + if (params->fogMode & FOG_CONSTANT) \ + { \ + src_r += params->fogColor.r; \ + src_g += params->fogColor.g; \ + src_b += params->fogColor.b; \ + } \ + else \ + { \ + int fog_r, fog_g, fog_b, fog_a; \ + \ + if (!(params->fogMode & FOG_ADD)) \ + { \ + fog_r = params->fogColor.r; \ + fog_g = params->fogColor.g; \ + fog_b = params->fogColor.b; \ + } \ + else \ + fog_r = fog_g = fog_b = 0; \ + \ + if (!(params->fogMode & FOG_MULT)) \ + { \ + fog_r -= src_r; \ + fog_g -= src_g; \ + fog_b -= src_b; \ + } \ + \ + if (params->fogMode & FOG_Z) \ + fog_a = (z >> 20) & 0xff; \ + else if (params->fogMode & FOG_ALPHA) \ + fog_a = CLAMP(ia >> 12); \ + else \ + { \ + int fog_idx = (w_depth >> 10) & 0x3f; \ + \ + fog_a = params->fogTable[fog_idx].fog; \ + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10; \ + } \ + fog_a++; \ + \ + fog_r = (fog_r * fog_a) >> 8; \ + fog_g = (fog_g * fog_a) >> 8; \ + fog_b = (fog_b * fog_a) >> 8; \ + \ + if (params->fogMode & FOG_MULT) \ + { \ + src_r = fog_r; \ + src_g = fog_g; \ + src_b = fog_b; \ + } \ + else \ + { \ + src_r += fog_r; \ + src_g += fog_g; \ + src_b += fog_b; \ + } \ + } \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while (0) + +#define ALPHA_TEST(src_a) \ + do \ + { \ + switch (alpha_func) \ + { \ + case AFUNC_NEVER: \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + case AFUNC_LESSTHAN: \ + if (!(src_a < a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_EQUAL: \ + if (!(src_a == a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_LESSTHANEQUAL: \ + if (!(src_a <= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHAN: \ + if (!(src_a > a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_NOTEQUAL: \ + if (!(src_a != a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHANEQUAL: \ + if (!(src_a >= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_ALWAYS: \ + break; \ + } \ + } while (0) + +#define ALPHA_BLEND(src_r, src_g, src_b, src_a) \ + do \ + { \ + int _a; \ + int newdest_r, newdest_g, newdest_b; \ + \ + switch (dest_afunc) \ + { \ + case AFUNC_AZERO: \ + newdest_r = newdest_g = newdest_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + newdest_r = (dest_r * src_a) / 255; \ + newdest_g = (dest_g * src_a) / 255; \ + newdest_b = (dest_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + newdest_r = (dest_r * src_r) / 255; \ + newdest_g = (dest_g * src_g) / 255; \ + newdest_b = (dest_b * src_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + newdest_r = (dest_r * dest_a) / 255; \ + newdest_g = (dest_g * dest_a) / 255; \ + newdest_b = (dest_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + newdest_r = dest_r; \ + newdest_g = dest_g; \ + newdest_b = dest_b; \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + newdest_r = (dest_r * (255-src_a)) / 255; \ + newdest_g = (dest_g * (255-src_a)) / 255; \ + newdest_b = (dest_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + newdest_r = (dest_r * (255-src_r)) / 255; \ + newdest_g = (dest_g * (255-src_g)) / 255; \ + newdest_b = (dest_b * (255-src_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + newdest_r = (dest_r * (255-dest_a)) / 255; \ + newdest_g = (dest_g * (255-dest_a)) / 255; \ + newdest_b = (dest_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ASATURATE: \ + _a = MIN(src_a, 1-dest_a); \ + newdest_r = (dest_r * _a) / 255; \ + newdest_g = (dest_g * _a) / 255; \ + newdest_b = (dest_b * _a) / 255; \ + break; \ + } \ + \ + switch (src_afunc) \ + { \ + case AFUNC_AZERO: \ + src_r = src_g = src_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + src_r = (src_r * src_a) / 255; \ + src_g = (src_g * src_a) / 255; \ + src_b = (src_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + src_r = (src_r * dest_r) / 255; \ + src_g = (src_g * dest_g) / 255; \ + src_b = (src_b * dest_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + src_r = (src_r * dest_a) / 255; \ + src_g = (src_g * dest_a) / 255; \ + src_b = (src_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + src_r = (src_r * (255-src_a)) / 255; \ + src_g = (src_g * (255-src_a)) / 255; \ + src_b = (src_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + src_r = (src_r * (255-dest_r)) / 255; \ + src_g = (src_g * (255-dest_g)) / 255; \ + src_b = (src_b * (255-dest_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + src_r = (src_r * (255-dest_a)) / 255; \ + src_g = (src_g * (255-dest_a)) / 255; \ + src_b = (src_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ACOLORBEFOREFOG: \ + break; \ + } \ + \ + src_r += newdest_r; \ + src_g += newdest_g; \ + src_b += newdest_b; \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while(0) + + +#define _rgb_sel ( params->fbzColorPath & 3) +#define a_sel ( (params->fbzColorPath >> 2) & 3) +#define cc_localselect ( params->fbzColorPath & (1 << 4)) +#define cca_localselect ( (params->fbzColorPath >> 5) & 3) +#define cc_localselect_override ( params->fbzColorPath & (1 << 7)) +#define cc_zero_other ( params->fbzColorPath & (1 << 8)) +#define cc_sub_clocal ( params->fbzColorPath & (1 << 9)) +#define cc_mselect ( (params->fbzColorPath >> 10) & 7) +#define cc_reverse_blend ( params->fbzColorPath & (1 << 13)) +#define cc_add ( (params->fbzColorPath >> 14) & 3) +#define cc_add_alocal ( params->fbzColorPath & (1 << 15)) +#define cc_invert_output ( params->fbzColorPath & (1 << 16)) +#define cca_zero_other ( params->fbzColorPath & (1 << 17)) +#define cca_sub_clocal ( params->fbzColorPath & (1 << 18)) +#define cca_mselect ( (params->fbzColorPath >> 19) & 7) +#define cca_reverse_blend ( params->fbzColorPath & (1 << 22)) +#define cca_add ( (params->fbzColorPath >> 23) & 3) +#define cca_invert_output ( params->fbzColorPath & (1 << 25)) +#define src_afunc ( (params->alphaMode >> 8) & 0xf) +#define dest_afunc ( (params->alphaMode >> 12) & 0xf) +#define alpha_func ( (params->alphaMode >> 1) & 7) +#define a_ref ( params->alphaMode >> 24) +#define depth_op ( (params->fbzMode >> 5) & 7) +#define dither ( params->fbzMode & FBZ_DITHER) +#define dither2x2 (params->fbzMode & FBZ_DITHER_2x2) + +#if (defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32) && !(defined __amd64__) +#include "vid_voodoo_codegen_x86.h" +#elif (defined __amd64__) +#include "vid_voodoo_codegen_x86-64.h" +#else +#define NO_CODEGEN +static int voodoo_recomp = 0; +#endif + +static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int ystart, int yend, int odd_even) +{ +/* int rgb_sel = params->fbzColorPath & 3; + int a_sel = (params->fbzColorPath >> 2) & 3; + int cc_localselect = params->fbzColorPath & (1 << 4); + int cca_localselect = (params->fbzColorPath >> 5) & 3; + int cc_localselect_override = params->fbzColorPath & (1 << 7); + int cc_zero_other = params->fbzColorPath & (1 << 8); + int cc_sub_clocal = params->fbzColorPath & (1 << 9); + int cc_mselect = (params->fbzColorPath >> 10) & 7; + int cc_reverse_blend = params->fbzColorPath & (1 << 13); + int cc_add = (params->fbzColorPath >> 14) & 3; + int cc_add_alocal = params->fbzColorPath & (1 << 15); + int cc_invert_output = params->fbzColorPath & (1 << 16); + int cca_zero_other = params->fbzColorPath & (1 << 17); + int cca_sub_clocal = params->fbzColorPath & (1 << 18); + int cca_mselect = (params->fbzColorPath >> 19) & 7; + int cca_reverse_blend = params->fbzColorPath & (1 << 22); + int cca_add = (params->fbzColorPath >> 23) & 3; + int cca_invert_output = params->fbzColorPath & (1 << 25); + int src_afunc = (params->alphaMode >> 8) & 0xf; + int dest_afunc = (params->alphaMode >> 12) & 0xf; + int alpha_func = (params->alphaMode >> 1) & 7; + int a_ref = params->alphaMode >> 24; + int depth_op = (params->fbzMode >> 5) & 7; + int dither = params->fbzMode & FBZ_DITHER;*/ + int c; + uint8_t (*voodoo_draw)(voodoo_state_t *state, voodoo_params_t *params, int x, int real_y); + + state->clamp_s = params->textureMode & TEXTUREMODE_TCLAMPS; + state->clamp_t = params->textureMode & TEXTUREMODE_TCLAMPT; +// int last_x; +// pclog("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir); + + for (c = 0; c <= LOD_MAX; c++) + { + state->tex[c] = &voodoo->tex_mem[params->tex_base[c] & voodoo->texture_mask]; + state->tex_w[c] = (uint16_t *)state->tex[c]; + } + + state->tformat = params->tformat; + + state->tex_w_mask = params->tex_w_mask; + state->tex_h_mask = params->tex_h_mask; + state->tex_shift = params->tex_shift; + + if ((params->fbzMode & 1) && (ystart < params->clipLowY)) + { + int dy = params->clipLowY - ystart; + + state->base_r += params->dRdY*dy; + state->base_g += params->dGdY*dy; + state->base_b += params->dBdY*dy; + state->base_a += params->dAdY*dy; + state->base_z += params->dZdY*dy; + state->tmu[0].base_s += params->tmu[0].dSdY*dy; + state->tmu[0].base_t += params->tmu[0].dTdY*dy; + state->tmu[0].base_w += params->tmu[0].dWdY*dy; + state->base_w += params->dWdY*dy; + state->xstart += state->dx1*dy; + state->xend += state->dx2*dy; + + ystart = params->clipLowY; + } + + if ((params->fbzMode & 1) && (yend > params->clipHighY)) + yend = params->clipHighY; + + state->y = ystart; +// yend--; + +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + voodoo_draw = voodoo_get_block(voodoo, params, state, odd_even); +#endif + +#if 0 + if (voodoo_output) + pclog("dxAB=%08x dxBC=%08x dxAC=%08x\n", state->dxAB, state->dxBC, state->dxAC); +#endif +// pclog("Start %i %i\n", ystart, voodoo->fbzMode & (1 << 17)); + for (; state->y < yend; state->y++) + { + int x, x2; + int real_y = (state->y << 4) + 8; + int start_x, start_x2; + int dx; + uint16_t *fb_mem, *aux_mem; + + state->ir = state->base_r; + state->ig = state->base_g; + state->ib = state->base_b; + state->ia = state->base_a; + state->z = state->base_z; + state->tmu0_s = state->tmu[0].base_s; + state->tmu0_t = state->tmu[0].base_t; + state->tmu0_w = state->tmu[0].base_w; + state->w = state->base_w; + + x = (state->vertexAx << 12) + ((state->dxAC * (real_y - state->vertexAy)) >> 4); + + if (real_y < state->vertexBy) + x2 = (state->vertexAx << 12) + ((state->dxAB * (real_y - state->vertexAy)) >> 4); + else + x2 = (state->vertexBx << 12) + ((state->dxBC * (real_y - state->vertexBy)) >> 4); + + if (params->fbzMode & (1 << 17)) + real_y = (voodoo->v_disp-1) - (real_y >> 4); + else + real_y >>= 4; + + if ((real_y & voodoo->odd_even_mask) != odd_even) + goto next_line; + + start_x = x; + + if (state->xdir > 0) + x2 -= (1 << 16); + else + x -= (1 << 16); + dx = ((x + 0x7000) >> 16) - (((state->vertexAx << 12) + 0x7000) >> 16); + start_x2 = x + 0x7000; + x = (x + 0x7000) >> 16; + x2 = (x2 + 0x7000) >> 16; + +#if 0 + if (voodoo_output) + pclog("%03i:%03i : Ax=%08x start_x=%08x dSdX=%016llx dx=%08x s=%08x -> ", x, state->y, state->vertexAx << 8, start_x, params->tmu[0].dTdX, dx, state->tmu0_t); +#endif + + state->ir += (params->dRdX * dx); + state->ig += (params->dGdX * dx); + state->ib += (params->dBdX * dx); + state->ia += (params->dAdX * dx); + state->z += (params->dZdX * dx); + state->tmu0_s += (params->tmu[0].dSdX * dx); + state->tmu0_t += (params->tmu[0].dTdX * dx); + state->tmu0_w += (params->tmu[0].dWdX * dx); + state->w += (params->dWdX * dx); + +#if 0 + if (voodoo_output) + pclog("%08llx %lli %lli\n", state->tmu0_t, state->tmu0_t >> (18+state->lod), (state->tmu0_t + (1 << 17+state->lod)) >> (18+state->lod)); +#endif + + if (params->fbzMode & 1) + { + if (state->xdir > 0) + { + if (x < params->clipLeft) + { + int dx = params->clipLeft - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipLeft; + } + if (x2 > params->clipRight) + x2 = params->clipRight; + } + else + { + if (x > params->clipRight) + { + int dx = params->clipRight - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipRight; + } + if (x2 < params->clipLeft) + x2 = params->clipLeft; + } + } + + if (x2 < x && state->xdir > 0) + goto next_line; + if (x2 > x && state->xdir < 0) + goto next_line; + + state->fb_mem = fb_mem = &voodoo->fb_mem[params->draw_offset + (real_y * voodoo->row_width)]; + state->aux_mem = aux_mem = &voodoo->fb_mem[params->aux_offset + (real_y * voodoo->row_width)]; + +#if 0 + if (voodoo_output) + pclog("%03i: x=%08x x2=%08x xstart=%08x xend=%08x dx=%08x start_x2=%08x\n", state->y, x, x2, state->xstart, state->xend, dx, start_x2); +#endif + + state->pixel_count = 0; + state->x = x; + state->x2 = x2; + +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + { + voodoo_draw(state, params, x, real_y); + } + else +#endif + do + { + start_x = x; + voodoo->pixel_count[odd_even]++; + voodoo->fbiPixelsIn++; +#if 0 + if (voodoo_output) + pclog(" X=%03i T=%08x\n", x, state->tmu0_t); +#endif +// if (voodoo->fbzMode & FBZ_RGB_WMASK) + { + int update = 1; + uint8_t cother_r, cother_g, cother_b, aother; + uint8_t clocal_r, clocal_g, clocal_b, alocal; + int src_r, src_g, src_b, src_a; + int msel_r, msel_g, msel_b, msel_a; + uint8_t dest_r, dest_g, dest_b, dest_a; + uint16_t dat; + uint16_t aux_dat; + int sel; + int32_t new_depth, w_depth; + + if (state->w & 0xffff00000000) + w_depth = 0; + else if (!(state->w & 0xffff0000)) + w_depth = 0xf001; + else + { + int exp = fls((uint16_t)((uint32_t)state->w >> 16)); + int mant = ((~(uint32_t)state->w >> (19 - exp))) & 0xfff; + w_depth = (exp << 12) + mant + 1; + if (w_depth > 0xffff) + w_depth = 0xffff; + } + +// w_depth = CLAMP16(w_depth); + + if (params->fbzMode & FBZ_W_BUFFER) + new_depth = w_depth; + else + new_depth = CLAMP16(state->z >> 12); + + if (params->fbzMode & FBZ_DEPTH_BIAS) + new_depth = (new_depth + params->zaColor) & 0xffff; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = aux_mem[x]; + + DEPTH_TEST(); + } + + dat = fb_mem[x]; + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (params->textureMode & 1) + { + int64_t _w = 0; + if (state->tmu0_w) + _w = (int64_t)((1ULL << 48) / state->tmu0_w); + + state->tex_s = (int32_t)(((state->tmu0_s >> 14) * _w) >> 30); + state->tex_t = (int32_t)(((state->tmu0_t >> 14) * _w) >> 30); +// state->lod = state->tmu[0].lod + (int)(log2((double)_w / (double)(1 << 19)) * 256.0); + state->lod = state->tmu[0].lod + (fastlog(_w) - (19 << 8)); + } + else + { + state->tex_s = (int32_t)(state->tmu0_s >> (14+14)); + state->tex_t = (int32_t)(state->tmu0_t >> (14+14)); + state->lod = state->tmu[0].lod; + } + + if (state->lod < state->lod_min) + state->lod = state->lod_min; + else if (state->lod > state->lod_max) + state->lod = state->lod_max; + state->lod >>= 8; + + voodoo_get_texture(voodoo, params, state); + + if ((params->fbzMode & FBZ_CHROMAKEY) && + state->tex_r == params->chromaKey_r && + state->tex_g == params->chromaKey_g && + state->tex_b == params->chromaKey_b) + { + voodoo->fbiChromaFail++; + goto skip_pixel; + } + } + + if (voodoo->trexInit1 & (1 << 18)) + { + state->tex_r = state->tex_g = 0; + state->tex_b = 1; + } + + if (cc_localselect_override) + sel = (state->tex_a & 0x80) ? 1 : 0; + else + sel = cc_localselect; + + if (sel) + { + clocal_r = (params->color0 >> 16) & 0xff; + clocal_g = (params->color0 >> 8) & 0xff; + clocal_b = params->color0 & 0xff; + } + else + { + clocal_r = CLAMP(state->ir >> 12); + clocal_g = CLAMP(state->ig >> 12); + clocal_b = CLAMP(state->ib >> 12); + } + + switch (_rgb_sel) + { + case CC_LOCALSELECT_ITER_RGB: /*Iterated RGB*/ + cother_r = CLAMP(state->ir >> 12); + cother_g = CLAMP(state->ig >> 12); + cother_b = CLAMP(state->ib >> 12); + break; + + case CC_LOCALSELECT_TEX: /*TREX Color Output*/ + cother_r = state->tex_r; + cother_g = state->tex_g; + cother_b = state->tex_b; + break; + + case CC_LOCALSELECT_COLOR1: /*Color1 RGB*/ + cother_r = (params->color1 >> 16) & 0xff; + cother_g = (params->color1 >> 8) & 0xff; + cother_b = params->color1 & 0xff; + break; + + case CC_LOCALSELECT_LFB: /*Linear Frame Buffer*/ + cother_r = src_r; + cother_g = src_g; + cother_b = src_b; + break; + } + + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + alocal = CLAMP(state->ia >> 12); + break; + + case CCA_LOCALSELECT_COLOR0: + alocal = (params->color0 >> 24) & 0xff; + break; + + case CCA_LOCALSELECT_ITER_Z: + alocal = CLAMP(state->z >> 20); + break; + + default: + alocal = 0xff; + break; + } + + switch (a_sel) + { + case A_SEL_ITER_A: + aother = CLAMP(state->ia >> 12); + break; + case A_SEL_TEX: + aother = state->tex_a; + break; + case A_SEL_COLOR1: + aother = (params->color1 >> 24) & 0xff; + break; + default: + aother = 0; + break; + } + + if (cc_zero_other) + { + src_r = 0; + src_g = 0; + src_b = 0; + } + else + { + src_r = cother_r; + src_g = cother_g; + src_b = cother_b; + } + + if (cca_zero_other) + src_a = 0; + else + src_a = aother; + + if (cc_sub_clocal) + { + src_r -= clocal_r; + src_g -= clocal_g; + src_b -= clocal_b; + } + + if (cca_sub_clocal) + src_a -= alocal; + + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + case CC_MSELECT_CLOCAL: + msel_r = clocal_r; + msel_g = clocal_g; + msel_b = clocal_b; + break; + case CC_MSELECT_AOTHER: + msel_r = aother; + msel_g = aother; + msel_b = aother; + break; + case CC_MSELECT_ALOCAL: + msel_r = alocal; + msel_g = alocal; + msel_b = alocal; + break; + case CC_MSELECT_TEX: + msel_r = state->tex_a; + msel_g = state->tex_a; + msel_b = state->tex_a; + break; + + default: + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + } + + switch (cca_mselect) + { + case CCA_MSELECT_ZERO: + msel_a = 0; + break; + case CCA_MSELECT_ALOCAL: + msel_a = alocal; + break; + case CCA_MSELECT_AOTHER: + msel_a = aother; + break; + case CCA_MSELECT_ALOCAL2: + msel_a = alocal; + break; + case CCA_MSELECT_TEX: + msel_a = state->tex_a; + break; + + default: + msel_a = 0; + break; + } + + if (!cc_reverse_blend) + { + msel_r ^= 0xff; + msel_g ^= 0xff; + msel_b ^= 0xff; + } + msel_r++; + msel_g++; + msel_b++; + + if (!cca_reverse_blend) + msel_a ^= 0xff; + msel_a++; + + src_r = (src_r * msel_r) >> 8; + src_g = (src_g * msel_g) >> 8; + src_b = (src_b * msel_b) >> 8; + src_a = (src_a * msel_a) >> 8; + + switch (cc_add) + { + case CC_ADD_CLOCAL: + src_r += clocal_r; + src_g += clocal_g; + src_b += clocal_b; + break; + case CC_ADD_ALOCAL: + src_r += alocal; + src_g += alocal; + src_b += alocal; + break; + } + + if (cca_add) + src_a += alocal; + + src_r = CLAMP(src_r); + src_g = CLAMP(src_g); + src_b = CLAMP(src_b); + src_a = CLAMP(src_a); + + if (cc_invert_output) + { + src_r ^= 0xff; + src_g ^= 0xff; + src_b ^= 0xff; + } + if (cca_invert_output) + src_a ^= 0xff; + + if (params->fogMode & FOG_ENABLE) + APPLY_FOG(src_r, src_g, src_b, state->z, state->ia); + + if (params->alphaMode & 1) + ALPHA_TEST(src_a); + + if (params->alphaMode & (1 << 4)) + ALPHA_BLEND(src_r, src_g, src_b, src_a); + + if (update) + { + if (dither) + { + if (dither2x2) + { + src_r = dither_rb2x2[src_r][real_y & 1][x & 1]; + src_g = dither_g2x2[src_g][real_y & 1][x & 1]; + src_b = dither_rb2x2[src_b][real_y & 1][x & 1]; + } + else + { + src_r = dither_rb[src_r][real_y & 3][x & 3]; + src_g = dither_g[src_g][real_y & 3][x & 3]; + src_b = dither_rb[src_b][real_y & 3][x & 3]; + } + } + else + { + src_r >>= 3; + src_g >>= 2; + src_b >>= 3; + } + + if (params->fbzMode & FBZ_RGB_WMASK) + fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); + if (params->fbzMode & FBZ_DEPTH_WMASK) + aux_mem[x] = new_depth; + } + } + voodoo_output &= ~2; + voodoo->fbiPixelsOut++; +skip_pixel: + if (state->xdir > 0) + { + state->ir += params->dRdX; + state->ig += params->dGdX; + state->ib += params->dBdX; + state->ia += params->dAdX; + state->z += params->dZdX; + state->tmu0_s += params->tmu[0].dSdX; + state->tmu0_t += params->tmu[0].dTdX; + state->tmu0_w += params->tmu[0].dWdX; + state->w += params->dWdX; + } + else + { + state->ir -= params->dRdX; + state->ig -= params->dGdX; + state->ib -= params->dBdX; + state->ia -= params->dAdX; + state->z -= params->dZdX; + state->tmu0_s -= params->tmu[0].dSdX; + state->tmu0_t -= params->tmu[0].dTdX; + state->tmu0_w -= params->tmu[0].dWdX; + state->w -= params->dWdX; + } + + x += state->xdir; + } while (start_x != x2); + + voodoo->pixel_count[odd_even] += state->pixel_count; + voodoo->fbiPixelsIn += state->pixel_count; + + if (voodoo->params.draw_offset == voodoo->params.front_offset) + voodoo->dirty_line[real_y] = 1; +next_line: + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } +} + +static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even) +{ + voodoo_state_t state; + int vertexAy_adjusted; + int vertexBy_adjusted; + int vertexCy_adjusted; + int dx, dy; + + uint64_t tempdx, tempdy; + uint64_t tempLOD; + int LOD; + int lodbias; + + voodoo->tri_count++; + + dx = 8 - (params->vertexAx & 0xf); + if ((params->vertexAx & 0xf) > 8) + dx += 16; + dy = 8 - (params->vertexAy & 0xf); + if ((params->vertexAy & 0xf) > 8) + dy += 16; + +/* pclog("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i %08x %08x %08x\n", odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0, + (float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0, + (float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0, (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat : 0, params->fbzColorPath, params->alphaMode, params->textureMode);*/ + + state.base_r = params->startR; + state.base_g = params->startG; + state.base_b = params->startB; + state.base_a = params->startA; + state.base_z = params->startZ; + state.tmu[0].base_s = params->tmu[0].startS; + state.tmu[0].base_t = params->tmu[0].startT; + state.tmu[0].base_w = params->tmu[0].startW; + state.base_w = params->startW; + + if (params->fbzColorPath & FBZ_PARAM_ADJUST) + { + state.base_r += (dx*params->dRdX + dy*params->dRdY) >> 4; + state.base_g += (dx*params->dGdX + dy*params->dGdY) >> 4; + state.base_b += (dx*params->dBdX + dy*params->dBdY) >> 4; + state.base_a += (dx*params->dAdX + dy*params->dAdY) >> 4; + state.base_z += (dx*params->dZdX + dy*params->dZdY) >> 4; + state.tmu[0].base_s += (dx*params->tmu[0].dSdX + dy*params->tmu[0].dSdY) >> 4; + state.tmu[0].base_t += (dx*params->tmu[0].dTdX + dy*params->tmu[0].dTdY) >> 4; + state.tmu[0].base_w += (dx*params->tmu[0].dWdX + dy*params->tmu[0].dWdY) >> 4; + state.base_w += (dx*params->dWdX + dy*params->dWdY) >> 4; + } + + tris++; + + state.vertexAy = params->vertexAy & ~0xffff0000; + if (state.vertexAy & 0x8000) + state.vertexAy |= 0xffff0000; + state.vertexBy = params->vertexBy & ~0xffff0000; + if (state.vertexBy & 0x8000) + state.vertexBy |= 0xffff0000; + state.vertexCy = params->vertexCy & ~0xffff0000; + if (state.vertexCy & 0x8000) + state.vertexCy |= 0xffff0000; + + state.vertexAx = params->vertexAx & ~0xffff0000; + if (state.vertexAx & 0x8000) + state.vertexAx |= 0xffff0000; + state.vertexBx = params->vertexBx & ~0xffff0000; + if (state.vertexBx & 0x8000) + state.vertexBx |= 0xffff0000; + state.vertexCx = params->vertexCx & ~0xffff0000; + if (state.vertexCx & 0x8000) + state.vertexCx |= 0xffff0000; + + vertexAy_adjusted = (state.vertexAy+7) >> 4; + vertexBy_adjusted = (state.vertexBy+7) >> 4; + vertexCy_adjusted = (state.vertexCy+7) >> 4; + + if (state.vertexBy - state.vertexAy) + state.dxAB = (int)((((int64_t)state.vertexBx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexBy - state.vertexAy); + else + state.dxAB = 0; + if (state.vertexCy - state.vertexAy) + state.dxAC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexCy - state.vertexAy); + else + state.dxAC = 0; + if (state.vertexCy - state.vertexBy) + state.dxBC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexBx << 12)) << 4) / (int)(state.vertexCy - state.vertexBy); + else + state.dxBC = 0; + + state.lod_min = (params->tLOD & 0x3f) << 6; + state.lod_max = ((params->tLOD >> 6) & 0x3f) << 6; + if (state.lod_max > 0x800) + state.lod_max = 0x800; + state.xstart = state.xend = state.vertexAx << 8; + state.xdir = params->sign ? -1 : 1; + + state.y = (state.vertexAy + 8) >> 4; + state.ydir = 1; + + tempdx = (params->tmu[0].dSdX >> 14) * (params->tmu[0].dSdX >> 14) + (params->tmu[0].dTdX >> 14) * (params->tmu[0].dTdX >> 14); + tempdy = (params->tmu[0].dSdY >> 14) * (params->tmu[0].dSdY >> 14) + (params->tmu[0].dTdY >> 14) * (params->tmu[0].dTdY >> 14); + + if (tempdx > tempdy) + tempLOD = tempdx; + else + tempLOD = tempdy; + + LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); + LOD >>= 2; + + lodbias = (params->tLOD >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[0].lod = LOD + (lodbias << 6); + + state.palette = params->palette; + + voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even); +} + +static inline void wake_render_thread(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_render_thread[0]); /*Wake up render thread if moving from idle*/ + if (voodoo->render_threads == 2) + thread_set_event(voodoo->wake_render_thread[1]); /*Wake up render thread if moving from idle*/ +} + +static inline void wait_for_render_thread_idle(voodoo_t *voodoo) +{ + while (!PARAM_EMPTY_1 || (voodoo->render_threads == 2 && !PARAM_EMPTY_2) || voodoo->render_voodoo_busy[0] || (voodoo->render_threads == 2 && voodoo->render_voodoo_busy[1])) + { + wake_render_thread(voodoo); + if (!PARAM_EMPTY_1 || voodoo->render_voodoo_busy[0]) + thread_wait_event(voodoo->render_not_full_event[0], 1); + if (voodoo->render_threads == 2 && (!PARAM_EMPTY_2 || voodoo->render_voodoo_busy[1])) + thread_wait_event(voodoo->render_not_full_event[1], 1); + } +} + +static void render_thread(void *param, int odd_even) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (1) + { + thread_set_event(voodoo->render_not_full_event[odd_even]); + thread_wait_event(voodoo->wake_render_thread[odd_even], -1); + thread_reset_event(voodoo->wake_render_thread[odd_even]); + voodoo->render_voodoo_busy[odd_even] = 1; + + while (!(odd_even ? PARAM_EMPTY_2 : PARAM_EMPTY_1)) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + voodoo_params_t *params = &voodoo->params_buffer[voodoo->params_read_idx[odd_even] & PARAM_MASK]; + + voodoo_triangle(voodoo, params, odd_even); + + voodoo->params_read_idx[odd_even]++; + + if ((odd_even ? PARAM_ENTRIES_2 : PARAM_ENTRIES_1) > (PARAM_SIZE - 10)) + thread_set_event(voodoo->render_not_full_event[odd_even]); + + end_time = timer_read(); + voodoo_render_time[odd_even] += end_time - start_time; + } + + voodoo->render_voodoo_busy[odd_even] = 0; + } +} + +static void render_thread_1(void *param) +{ + render_thread(param, 0); +} +static void render_thread_2(void *param) +{ + render_thread(param, 1); +} + +static inline void queue_triangle(voodoo_t *voodoo, voodoo_params_t *params) +{ + voodoo_params_t *params_new = &voodoo->params_buffer[voodoo->params_write_idx & PARAM_MASK]; + + while (PARAM_FULL_1 || (voodoo->render_threads == 2 && PARAM_FULL_2)) + { + thread_reset_event(voodoo->render_not_full_event[0]); + if (voodoo->render_threads == 2) + thread_reset_event(voodoo->render_not_full_event[1]); + if (PARAM_FULL_1) + { + thread_wait_event(voodoo->render_not_full_event[0], -1); /*Wait for room in ringbuffer*/ + } + if (voodoo->render_threads == 2 && PARAM_FULL_2) + { + thread_wait_event(voodoo->render_not_full_event[1], -1); /*Wait for room in ringbuffer*/ + } + } + + memcpy(params_new, params, sizeof(voodoo_params_t) - sizeof(voodoo->palette)); + + /*Copy palette data if required*/ + switch (params->tformat) + { + case TEX_PAL8: case TEX_APAL88: + memcpy(params_new->palette, voodoo->palette, sizeof(voodoo->palette)); + break; + case TEX_Y4I2Q2: + memcpy(params_new->palette, voodoo->ncc_lookup[(params->textureMode & TEXTUREMODE_NCC_SEL) ? 1 : 0], sizeof(voodoo->palette)); + break; + } + + voodoo->params_write_idx++; + + if (PARAM_ENTRIES_1 < 4 || (voodoo->render_threads == 2 && PARAM_ENTRIES_2 < 4)) + wake_render_thread(voodoo); +} + +static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) +{ + int y; + + if (params->fbzMode & FBZ_RGB_WMASK) + { + int r, g, b; + uint16_t col; + + r = ((params->color1 >> 16) >> 3) & 0x1f; + g = ((params->color1 >> 8) >> 2) & 0x3f; + b = (params->color1 >> 3) & 0x1f; + col = b | (g << 5) | (r << 11); + + for (y = params->clipLowY; y < params->clipHighY; y++) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + y*voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + cbuf[x] = col; + } + } + if (params->fbzMode & FBZ_DEPTH_WMASK) + { + for (y = params->clipLowY; y < params->clipHighY; y++) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y*voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } +} + +static uint32_t voodoo_reg_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + uint32_t temp; + + switch (addr & 0x3fc) + { + + case SST_lfbMode: + temp = voodoo->lfbMode; + break; + + case SST_fbiInit4: + temp = voodoo->fbiInit4; + break; + case SST_fbiInit0: + temp = voodoo->fbiInit0; + break; + case SST_fbiInit1: + temp = voodoo->fbiInit1 & ~5; /*Pass-thru board with one SST-1*/ + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x04) + temp = voodoo->dac_readdata; + else + temp = voodoo->fbiInit2; + break; + case SST_fbiInit3: + temp = voodoo->fbiInit3; + break; + + default: + fatal("voodoo_readl : bad addr %08X\n", addr); + temp = 0xffffffff; + } + + return temp; +} + +enum +{ + CHIP_FBI = 0x1, + CHIP_TREX0 = 0x2, + CHIP_TREX1 = 0x2, + CHIP_TREX2 = 0x2 +}; + +static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + union + { + uint32_t i; + float f; + } tempif; + int ad21 = addr & (1 << 21); + int chip = (addr >> 10) & 0xf; + if (!chip) + chip = 0xf; + + tempif.i = val; +//pclog("voodoo_write_l: addr=%08x val=%08x(%f) chip=%x\n", addr, val, tempif.f, chip); + addr &= 0x3fc; + + if ((voodoo->fbiInit3 & FBIINIT3_REMAP) && addr < 0x100 && ad21) + addr |= 0x400; + switch (addr) + { + case SST_swapbufferCMD: +// pclog(" start swap buffer command\n"); + + voodoo->disp_buffer = !voodoo->disp_buffer; + voodoo_recalc(voodoo); + + voodoo->params.swapbufferCMD = val; + +#if 0 + pclog("Swap buffer %08x %d %p\n", val, voodoo->swap_count, &voodoo->swap_count); +#endif +// voodoo->front_offset = params->front_offset; + wait_for_render_thread_idle(voodoo); + if (!(val & 1)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->front_offset = voodoo->params.front_offset; + voodoo->swap_count--; + } + else + { + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + + while (voodoo->swap_pending) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + if ((voodoo->swap_pending && voodoo->flush) || FIFO_ENTRIES == 65536) + { + /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ + memset(voodoo->dirty_line, 1, 1024); + voodoo->front_offset = voodoo->params.front_offset; + voodoo->swap_count--; + voodoo->swap_pending = 0; + break; + } + } + } + voodoo->cmd_read++; + break; + + case SST_vertexAx: case SST_remap_vertexAx: + voodoo->params.vertexAx = val & 0xffff; + break; + case SST_vertexAy: case SST_remap_vertexAy: + voodoo->params.vertexAy = val & 0xffff; + break; + case SST_vertexBx: case SST_remap_vertexBx: + voodoo->params.vertexBx = val & 0xffff; + break; + case SST_vertexBy: case SST_remap_vertexBy: + voodoo->params.vertexBy = val & 0xffff; + break; + case SST_vertexCx: case SST_remap_vertexCx: + voodoo->params.vertexCx = val & 0xffff; + break; + case SST_vertexCy: case SST_remap_vertexCy: + voodoo->params.vertexCy = val & 0xffff; + break; + + case SST_startR: case SST_remap_startR: + voodoo->params.startR = val & 0xffffff; + break; + case SST_startG: case SST_remap_startG: + voodoo->params.startG = val & 0xffffff; + break; + case SST_startB: case SST_remap_startB: + voodoo->params.startB = val & 0xffffff; + break; + case SST_startZ: case SST_remap_startZ: + voodoo->params.startZ = val; + break; + case SST_startA: case SST_remap_startA: + voodoo->params.startA = val & 0xffffff; + break; + case SST_startS: case SST_remap_startS: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = ((int64_t)(int32_t)val) << 14; + break; + case SST_startT: case SST_remap_startT: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = ((int64_t)(int32_t)val) << 14; + break; + case SST_startW: case SST_remap_startW: + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdX: case SST_remap_dRdX: + voodoo->params.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdX: case SST_remap_dGdX: + voodoo->params.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdX: case SST_remap_dBdX: + voodoo->params.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdX: case SST_remap_dZdX: + voodoo->params.dZdX = val; + break; + case SST_dAdX: case SST_remap_dAdX: + voodoo->params.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdX: case SST_remap_dSdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdX: case SST_remap_dTdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdX: case SST_remap_dWdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdY: case SST_remap_dRdY: + voodoo->params.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdY: case SST_remap_dGdY: + voodoo->params.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdY: case SST_remap_dBdY: + voodoo->params.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdY: case SST_remap_dZdY: + voodoo->params.dZdY = val; + break; + case SST_dAdY: case SST_remap_dAdY: + voodoo->params.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdY: case SST_remap_dSdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdY: case SST_remap_dTdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdY: case SST_remap_dWdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(int32_t)val << 2; + break; + + case SST_triangleCMD: case SST_remap_triangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty) + voodoo_update_ncc(voodoo); + voodoo->ncc_dirty = 0; + + queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fvertexAx: case SST_remap_fvertexAx: + voodoo->fvertexAx.i = val; + voodoo->params.vertexAx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAx.f * 16.0f) & 0xffff; + break; + case SST_fvertexAy: case SST_remap_fvertexAy: + voodoo->fvertexAy.i = val; + voodoo->params.vertexAy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAy.f * 16.0f) & 0xffff; + break; + case SST_fvertexBx: case SST_remap_fvertexBx: + voodoo->fvertexBx.i = val; + voodoo->params.vertexBx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBx.f * 16.0f) & 0xffff; + break; + case SST_fvertexBy: case SST_remap_fvertexBy: + voodoo->fvertexBy.i = val; + voodoo->params.vertexBy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBy.f * 16.0f) & 0xffff; + break; + case SST_fvertexCx: case SST_remap_fvertexCx: + voodoo->fvertexCx.i = val; + voodoo->params.vertexCx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCx.f * 16.0f) & 0xffff; + break; + case SST_fvertexCy: case SST_remap_fvertexCy: + voodoo->fvertexCy.i = val; + voodoo->params.vertexCy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCy.f * 16.0f) & 0xffff; + break; + + case SST_fstartR: case SST_remap_fstartR: + tempif.i = val; + voodoo->params.startR = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartG: case SST_remap_fstartG: + tempif.i = val; + voodoo->params.startG = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartB: case SST_remap_fstartB: + tempif.i = val; + voodoo->params.startB = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartZ: case SST_remap_fstartZ: + tempif.i = val; + voodoo->params.startZ = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartA: case SST_remap_fstartA: + tempif.i = val; + voodoo->params.startA = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartS: case SST_remap_fstartS: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartT: case SST_remap_fstartT: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartW: case SST_remap_fstartW: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdX: case SST_remap_fdRdX: + tempif.i = val; + voodoo->params.dRdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdX: case SST_remap_fdGdX: + tempif.i = val; + voodoo->params.dGdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdX: case SST_remap_fdBdX: + tempif.i = val; + voodoo->params.dBdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdX: case SST_remap_fdZdX: + tempif.i = val; + voodoo->params.dZdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdX: case SST_remap_fdAdX: + tempif.i = val; + voodoo->params.dAdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdX: case SST_remap_fdSdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdX: case SST_remap_fdTdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdX: case SST_remap_fdWdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdY: case SST_remap_fdRdY: + tempif.i = val; + voodoo->params.dRdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdY: case SST_remap_fdGdY: + tempif.i = val; + voodoo->params.dGdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdY: case SST_remap_fdBdY: + tempif.i = val; + voodoo->params.dBdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdY: case SST_remap_fdZdY: + tempif.i = val; + voodoo->params.dZdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdY: case SST_remap_fdAdY: + tempif.i = val; + voodoo->params.dAdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdY: case SST_remap_fdSdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdY: case SST_remap_fdTdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdY: case SST_remap_fdWdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_ftriangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty) + voodoo_update_ncc(voodoo); + voodoo->ncc_dirty = 0; + + queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fbzColorPath: + voodoo->params.fbzColorPath = val; + voodoo->rgb_sel = val & 3; + break; + + case SST_fogMode: + voodoo->params.fogMode = val; + break; + case SST_alphaMode: + voodoo->params.alphaMode = val; + break; + case SST_fbzMode: + voodoo->params.fbzMode = val; + voodoo_recalc(voodoo); + break; + case SST_lfbMode: + voodoo->lfbMode = val; + voodoo_recalc(voodoo); + break; + + case SST_clipLeftRight: + voodoo->params.clipRight = val & 0x3ff; + voodoo->params.clipLeft = (val >> 16) & 0x3ff; + break; + case SST_clipLowYHighY: + voodoo->params.clipHighY = val & 0x3ff; + voodoo->params.clipLowY = (val >> 16) & 0x3ff; + break; + + case SST_nopCMD: + voodoo->cmd_read++; + voodoo->fbiPixelsIn = 0; + voodoo->fbiChromaFail = 0; + voodoo->fbiZFuncFail = 0; + voodoo->fbiAFuncFail = 0; + voodoo->fbiPixelsOut = 0; + break; + case SST_fastfillCMD: + wait_for_render_thread_idle(voodoo); + voodoo_fastfill(voodoo, &voodoo->params); + voodoo->cmd_read++; + break; + + case SST_fogColor: + voodoo->params.fogColor.r = (val >> 16) & 0xff; + voodoo->params.fogColor.g = (val >> 8) & 0xff; + voodoo->params.fogColor.b = val & 0xff; + break; + + case SST_zaColor: + voodoo->params.zaColor = val; + break; + case SST_chromaKey: + voodoo->params.chromaKey_r = (val >> 16) & 0xff; + voodoo->params.chromaKey_g = (val >> 8) & 0xff; + voodoo->params.chromaKey_b = val & 0xff; + voodoo->params.chromaKey = val & 0xffffff; + break; + + case SST_color0: + voodoo->params.color0 = val; + break; + case SST_color1: + voodoo->params.color1 = val; + break; + + case SST_fogTable00: case SST_fogTable01: case SST_fogTable02: case SST_fogTable03: + case SST_fogTable04: case SST_fogTable05: case SST_fogTable06: case SST_fogTable07: + case SST_fogTable08: case SST_fogTable09: case SST_fogTable0a: case SST_fogTable0b: + case SST_fogTable0c: case SST_fogTable0d: case SST_fogTable0e: case SST_fogTable0f: + case SST_fogTable10: case SST_fogTable11: case SST_fogTable12: case SST_fogTable13: + case SST_fogTable14: case SST_fogTable15: case SST_fogTable16: case SST_fogTable17: + case SST_fogTable18: case SST_fogTable19: case SST_fogTable1a: case SST_fogTable1b: + case SST_fogTable1c: case SST_fogTable1d: case SST_fogTable1e: case SST_fogTable1f: + addr = (addr - SST_fogTable00) >> 1; + voodoo->params.fogTable[addr].dfog = val & 0xff; + voodoo->params.fogTable[addr].fog = (val >> 8) & 0xff; + voodoo->params.fogTable[addr+1].dfog = (val >> 16) & 0xff; + voodoo->params.fogTable[addr+1].fog = (val >> 24) & 0xff; + break; + + case SST_textureMode: + voodoo->params.textureMode = val; + voodoo->params.tformat = (val >> 8) & 0xf; + break; + case SST_tLOD: + voodoo->params.tLOD = val; + voodoo_recalc_tex(voodoo); + break; + + case SST_texBaseAddr: +// pclog("Write texBaseAddr %08x\n", val); + voodoo->params.texBaseAddr = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo); + break; + case SST_texBaseAddr1: + voodoo->params.texBaseAddr1 = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo); + break; + case SST_texBaseAddr2: + voodoo->params.texBaseAddr2 = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo); + break; + case SST_texBaseAddr38: + voodoo->params.texBaseAddr38 = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo); + break; + + case SST_trexInit1: + voodoo->trexInit1 = val; + break; + + case SST_nccTable0_Y0: + voodoo->nccTable[0].y[0] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable0_Y1: + voodoo->nccTable[0].y[1] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable0_Y2: + voodoo->nccTable[0].y[2] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable0_Y3: + voodoo->nccTable[0].y[3] = val; + voodoo->ncc_dirty = 1; + break; + + case SST_nccTable0_I0: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].i[0] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_I2: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].i[2] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_Q0: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].q[0] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_Q2: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].q[2] = val; + voodoo->ncc_dirty = 1; + break; + } + if (val & (1 << 31)) + { + int p = (val >> 23) & 0xfe; + voodoo->palette[p].u = val | 0xff000000; + } + break; + + case SST_nccTable0_I1: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].i[1] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_I3: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].i[3] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_Q1: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].q[1] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_Q3: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].q[3] = val; + voodoo->ncc_dirty = 1; + break; + } + if (val & (1 << 31)) + { + int p = ((val >> 23) & 0xfe) | 0x01; + voodoo->palette[p].u = val | 0xff000000; + } + break; + + case SST_nccTable1_Y0: + voodoo->nccTable[1].y[0] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Y1: + voodoo->nccTable[1].y[1] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Y2: + voodoo->nccTable[1].y[2] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Y3: + voodoo->nccTable[1].y[3] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_I0: + voodoo->nccTable[1].i[0] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_I1: + voodoo->nccTable[1].i[1] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_I2: + voodoo->nccTable[1].i[2] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_I3: + voodoo->nccTable[1].i[3] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Q0: + voodoo->nccTable[1].q[0] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Q1: + voodoo->nccTable[1].q[1] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Q2: + voodoo->nccTable[1].q[2] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Q3: + voodoo->nccTable[1].q[3] = val; + voodoo->ncc_dirty = 1; + break; + } +} + + +static uint16_t voodoo_fb_readw(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint16_t temp; + + x = (addr >> 1) & 0x3ff; + y = (addr >> 11) & 0x3ff; + read_addr = voodoo->fb_read_offset + (x << 1) + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffff; + + temp = *(uint16_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// pclog("voodoo_fb_readw : %08X %08X %i %i %08X %08X %08x:%08x %i\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++); + return temp; +} +static uint32_t voodoo_fb_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint32_t temp; + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + read_addr = voodoo->fb_read_offset + x + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffffffff; + + temp = *(uint32_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// pclog("voodoo_fb_readl : %08X %08x %08X x=%i y=%i %08X %08X %08x:%08x %i ro=%08x rw=%i\n", addr, read_addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++, voodoo->fb_read_offset, voodoo->row_width); + return temp; +} + +static inline uint16_t do_dither(voodoo_params_t *params, rgba8_t col, int x, int y) +{ + int r, g, b; + + if (dither) + { + if (dither2x2) + { + r = dither_rb2x2[col.r][y & 1][x & 1]; + g = dither_g2x2[col.g][y & 1][x & 1]; + b = dither_rb2x2[col.b][y & 1][x & 1]; + } + else + { + r = dither_rb[col.r][y & 3][x & 3]; + g = dither_g[col.g][y & 3][x & 3]; + b = dither_rb[col.b][y & 3][x & 3]; + } + } + else + { + r = col.r >> 3; + g = col.g >> 2; + b = col.b >> 3; + } + + return b | (g << 5) | (r << 11); +} + +static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data; + uint16_t depth_data; + uint8_t alpha_data; + int write_mask; + + depth_data = voodoo->params.zaColor & 0xffff; + alpha_data = voodoo->params.zaColor >> 24; + +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// pclog("voodoo_fb_writew : %08X %04X\n", addr, val); + + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data = rgb565[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_RGB555: + colour_data = argb1555[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_ARGB1555: + colour_data = argb1555[val]; + alpha_data = colour_data.a; + write_mask = LFB_WRITE_COLOUR; + break; + + default: + fatal("voodoo_fb_writew : bad LFB format %08X\n", voodoo->lfbMode); + } + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (voodoo->fb_write_offset == voodoo->params.front_offset) + voodoo->dirty_line[y] = 1; + + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// pclog("fb_writew %08x %i %i %i %08x\n", addr, x, y, voodoo->row_width, write_addr); + + if (voodoo->lfbMode & 0x100) + { + { + rgba8_t write_data = colour_data; + uint16_t new_depth = depth_data; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int32_t w_depth = new_depth; + int32_t ia = alpha_data << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, x >> 1, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + x = x; + } + } + else + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data, x >> 1, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data; + } +} + + +static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data[2]; + uint16_t depth_data[2]; + uint8_t alpha_data[2]; + int write_mask, count = 1; + + depth_data[0] = depth_data[1] = voodoo->params.zaColor & 0xffff; + alpha_data[0] = alpha_data[1] = voodoo->params.zaColor >> 24; +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// pclog("voodoo_fb_writel : %08X %08X\n", addr, val); + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data[0] = rgb565[val & 0xffff]; + colour_data[1] = rgb565[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_RGB555: + colour_data[0] = argb1555[val & 0xffff]; + colour_data[1] = argb1555[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_ARGB1555: + colour_data[0] = argb1555[val & 0xffff]; + alpha_data[0] = colour_data[0].a; + colour_data[1] = argb1555[val >> 16]; + alpha_data[1] = colour_data[1].a; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + + case LFB_FORMAT_ARGB8888: + colour_data[0].b = val & 0xff; + colour_data[0].g = (val >> 8) & 0xff; + colour_data[0].r = (val >> 16) & 0xff; + alpha_data[0] = (val >> 24) & 0xff; + write_mask = LFB_WRITE_COLOUR; + addr >>= 1; + break; + + case LFB_FORMAT_DEPTH: + depth_data[0] = val; + depth_data[1] = val >> 16; + write_mask = LFB_WRITE_DEPTH; + count = 2; + break; + + default: + fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo->lfbMode); + } + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (voodoo->fb_write_offset == voodoo->params.front_offset) + voodoo->dirty_line[y] = 1; + + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// pclog("fb_writel %08x x=%i y=%i rw=%i %08x wo=%08x\n", addr, x, y, voodoo->row_width, write_addr, voodoo->fb_write_offset); + + if (voodoo->lfbMode & 0x100) + { + int c; + + for (c = 0; c < count; c++) + { + rgba8_t write_data = colour_data[c]; + uint16_t new_depth = depth_data[c]; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int32_t w_depth = new_depth; + int32_t ia = alpha_data[c] << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data[c]); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data[c]); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, (x >> 1) + c, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + write_addr += 2; + write_addr_aux += 2; + } + } + else + { + int c; + + for (c = 0; c < count; c++) + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data[c], (x >> 1) + c, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data[c]; + + write_addr += 2; + write_addr_aux += 2; + } + } +} + +static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) +{ + int lod, s, t; + voodoo_t *voodoo = (voodoo_t *)p; + + if (addr & 0x600000) + return; /*TREX != 0*/ + +// pclog("voodoo_tex_writel : %08X %08X %i\n", addr, val, voodoo->params.tformat); + + lod = (addr >> 17) & 0xf; + t = (addr >> 9) & 0xff; + if (voodoo->params.tformat & 8) + s = (addr >> 1) & 0xfe; + else + { + if (voodoo->params.textureMode & (1 << 31)) + s = addr & 0xfc; + else + s = (addr >> 1) & 0xfc; + } + + if (lod > LOD_MAX) + return; + +// if (addr >= 0x200000) +// return; + + if (voodoo->params.tformat & 8) + addr = voodoo->params.tex_base[lod] + s*2 + (t << voodoo->params.tex_shift[lod])*2; + else + addr = voodoo->params.tex_base[lod] + s + (t << voodoo->params.tex_shift[lod]); + *(uint32_t *)(&voodoo->tex_mem[addr & voodoo->texture_mask]) = val; +} + +static inline void wake_fifo_thread(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) +{ + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(voodoo->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(voodoo->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = addr_type; + + voodoo->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(voodoo); +} + +static uint16_t voodoo_readw(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + addr &= 0xffffff; + + cycles -= pci_nonburst_time; + + if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ + { + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + return voodoo_fb_readw(addr, voodoo); + } + + return 0xffff; +} + +static uint32_t voodoo_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + uint32_t temp; + int fifo_size; + voodoo->rd_count++; + addr &= 0xffffff; + + cycles -= pci_nonburst_time; + + if (addr & 0x800000) /*Texture*/ + { + } + else if (addr & 0x400000) /*Framebuffer*/ + { + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + temp = voodoo_fb_readl(addr, voodoo); + } + else switch (addr & 0x3fc) + { + case SST_status: + fifo_size = 0xffff - FIFO_ENTRIES; + temp = fifo_size << 12; + if (fifo_size < 0x40) + temp |= fifo_size; + else + temp |= 0x3f; + temp |= (voodoo->swap_count << 28); + if (voodoo->cmd_written - voodoo->cmd_read) + temp |= 0x380; /*Busy*/ + if (!voodoo->v_retrace) + temp |= 0x40; + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + + case SST_lfbMode: + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + temp = voodoo->lfbMode; + break; + + case SST_fbiPixelsIn: + temp = voodoo->fbiPixelsIn & 0xffffff; + break; + case SST_fbiChromaFail: + temp = voodoo->fbiChromaFail & 0xffffff; + break; + case SST_fbiZFuncFail: + temp = voodoo->fbiZFuncFail & 0xffffff; + break; + case SST_fbiAFuncFail: + temp = voodoo->fbiAFuncFail & 0xffffff; + break; + case SST_fbiPixelsOut: + temp = voodoo->fbiPixelsOut & 0xffffff; + break; + + case SST_fbiInit4: + temp = voodoo->fbiInit4; + break; + case SST_fbiInit0: + temp = voodoo->fbiInit0; + break; + case SST_fbiInit1: + temp = voodoo->fbiInit1 & ~5; /*Pass-thru board with one SST-1*/ + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x04) + temp = voodoo->dac_readdata; + else + temp = voodoo->fbiInit2; + break; + case SST_fbiInit3: + temp = voodoo->fbiInit3; + break; + + default: + fatal("voodoo_readl : bad addr %08X\n", addr); + temp = 0xffffffff; + } + + return temp; +} + +static void voodoo_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo->wr_count++; + addr &= 0xffffff; + + if (addr == voodoo->last_write_addr+4) + cycles -= pci_burst_time; + else + cycles -= pci_nonburst_time; + voodoo->last_write_addr = addr; + + if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ + queue_command(voodoo, addr | FIFO_WRITEW_FB, val); +} + +static void voodoo_pixelclock_update(voodoo_t *voodoo) +{ + int m = (voodoo->dac_pll_regs[0] & 0x7f) + 2; + int n1 = ((voodoo->dac_pll_regs[0] >> 8) & 0x1f) + 2; + int n2 = ((voodoo->dac_pll_regs[0] >> 13) & 0x07); + float t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + double clock_const; + int line_length; + + if ((voodoo->dac_data[6] & 0xf0) == 0x20 || + (voodoo->dac_data[6] & 0xf0) == 0x60 || + (voodoo->dac_data[6] & 0xf0) == 0x70) + t /= 2.0f; + + line_length = (voodoo->hSync & 0xff) + ((voodoo->hSync >> 16) & 0x3ff); + +// pclog("Pixel clock %f MHz hsync %08x line_length %d\n", t, voodoo->hSync, line_length); + + voodoo->pixel_clock = t; + + clock_const = cpuclock / t; + voodoo->line_time = (int)((double)line_length * clock_const * (double)(1 << TIMER_SHIFT)); +} + +static void voodoo_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo->wr_count++; + addr &= 0xffffff; + + if (addr == voodoo->last_write_addr+4) + cycles -= pci_burst_time; + else + cycles -= pci_nonburst_time; + voodoo->last_write_addr = addr; + + if (addr & 0x800000) /*Texture*/ + { + voodoo->tex_count++; + queue_command(voodoo, addr | FIFO_WRITEL_TEX, val); + } + else if (addr & 0x400000) /*Framebuffer*/ + { + queue_command(voodoo, addr | FIFO_WRITEL_FB, val); + } + else switch (addr & 0x3fc) + { + case SST_swapbufferCMD: + voodoo->cmd_written++; + voodoo->swap_count++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + case SST_triangleCMD: + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + case SST_ftriangleCMD: + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + case SST_fastfillCMD: + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + case SST_nopCMD: + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + + case SST_fbiInit4: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit4 = val; + break; + case SST_backPorch: + voodoo->backPorch = val; + break; + case SST_videoDimensions: + voodoo->videoDimensions = val; + voodoo->h_disp = (val & 0xfff) + 1; + voodoo->v_disp = (val >> 16) & 0xfff; + break; + case SST_fbiInit0: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit0 = val; + svga_set_override(voodoo->svga, val & 1); + } + break; + case SST_fbiInit1: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit1 = val; + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit2 = val; + voodoo_recalc(voodoo); + } + break; + case SST_fbiInit3: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit3 = val; + break; + + case SST_hSync: + voodoo->hSync = val; + voodoo_pixelclock_update(voodoo); + break; + case SST_vSync: + voodoo->vSync = val; + voodoo->v_total = (val & 0xffff) + (val >> 16); + break; + + case SST_clutData: + voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff; + voodoo->clutData_dirty = 1; + break; + + case SST_dacData: + voodoo->dac_reg = (val >> 8) & 7; + voodoo->dac_readdata = 0xff; + if (val & 0x800) + { +// pclog(" dacData read %i %02X\n", voodoo->dac_reg, voodoo->dac_data[7]); + if (voodoo->dac_reg == 5) + { + switch (voodoo->dac_data[7]) + { + case 0x01: voodoo->dac_readdata = 0x55; break; + case 0x07: voodoo->dac_readdata = 0x71; break; + case 0x0b: voodoo->dac_readdata = 0x79; break; + } + } + else + voodoo->dac_readdata = voodoo->dac_data[voodoo->dac_reg]; + } + else + { + if (voodoo->dac_reg == 5) + { + if (!voodoo->dac_reg_ff) + voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff00) | val; + else + voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff) | (val << 8); +// pclog("Write PLL reg %x %04x\n", voodoo->dac_data[4] & 0xf, voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf]); + voodoo->dac_reg_ff = !voodoo->dac_reg_ff; + if (!voodoo->dac_reg_ff) + voodoo->dac_data[4]++; + + } + else + { + voodoo->dac_data[voodoo->dac_reg] = val & 0xff; + voodoo->dac_reg_ff = 0; + } + voodoo_pixelclock_update(voodoo); + } + break; + + default: + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + break; + } +} + +static void fifo_thread(void *param) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (1) + { + thread_set_event(voodoo->fifo_not_full_event); + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + voodoo->voodoo_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITEL_REG: + voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEW_FB: + wait_for_render_thread_idle(voodoo); + voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEL_FB: + wait_for_render_thread_idle(voodoo); + voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEL_TEX: + if (!(fifo->addr_type & 0x600000)) + { + wait_for_render_thread_idle(voodoo); + voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + } + break; + } + + voodoo->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(voodoo->fifo_not_full_event); + + end_time = timer_read(); + voodoo_time += end_time - start_time; + } + voodoo->voodoo_busy = 0; + + } +} + +static void voodoo_recalcmapping(voodoo_t *voodoo) +{ + if (voodoo->pci_enable && voodoo->memBaseAddr) + { +#if 0 + pclog("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo->memBaseAddr); +#endif + mem_mapping_set_addr(&voodoo->mapping, voodoo->memBaseAddr, 0x01000000); + } + else + { +#if 0 + pclog("voodoo_recalcmapping : disabled\n"); +#endif + mem_mapping_disable(&voodoo->mapping); + } +} + +uint8_t voodoo_pci_read(int func, int addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + +#if 0 + pclog("Voodoo PCI read %08X\n", addr); +#endif + switch (addr) + { + case 0x00: return 0x1a; /*3dfx*/ + case 0x01: return 0x12; + + case 0x02: return 0x01; /*SST-1 (Voodoo Graphics)*/ + case 0x03: return 0x00; + + case 0x04: return voodoo->pci_enable ? 0x02 : 0x00; /*Respond to memory accesses*/ + + case 0x08: return 2; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x10: return 0x00; /*memBaseAddr*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return voodoo->memBaseAddr >> 24; + + case 0x40: return voodoo->initEnable; + } + return 0; +} + +void voodoo_pci_write(int func, int addr, uint8_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + +#if 0 + pclog("Voodoo PCI write %04X %02X\n", addr, val); +#endif + switch (addr) + { + case 0x04: + voodoo->pci_enable = val & 2; + voodoo_recalcmapping(voodoo); + break; + + case 0x13: + voodoo->memBaseAddr = val << 24; + voodoo_recalcmapping(voodoo); + break; + + case 0x40: + voodoo->initEnable = val; + break; + } +} + +static void voodoo_calc_clutData(voodoo_t *voodoo) +{ + int c; + + for (c = 0; c < 256; c++) + { + voodoo->clutData256[c].r = (voodoo->clutData[c >> 3].r*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].r*(c & 7)) >> 3; + voodoo->clutData256[c].g = (voodoo->clutData[c >> 3].g*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].g*(c & 7)) >> 3; + voodoo->clutData256[c].b = (voodoo->clutData[c >> 3].b*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].b*(c & 7)) >> 3; + } + + for (c = 0; c < 65536; c++) + { + int r = (c >> 8) & 0xf8; + int g = (c >> 3) & 0xfc; + int b = (c << 3) & 0xf8; +// r |= (r >> 5); +// g |= (g >> 6); +// b |= (b >> 5); + + voodoo->video_16to32[c] = (voodoo->clutData256[r].r << 16) | (voodoo->clutData256[g].g << 8) | voodoo->clutData256[b].b; + } +} + +#define FILTCAP 64.0f /* Needs tuning to match DAC */ +#define FILTCAPG (FILTCAP / 2) + +static void voodoo_generate_filter(voodoo_t *voodoo) +{ + int g, h, i; + float difference, diffg; + float color; + float thiscol, thiscolg, lined; + + for (g=0;g<1024;g++) // pixel 1 + { + for (h=0;h<1024;h++) // pixel 2 + { + difference = h - g; + diffg = difference / 2; + + if (difference > FILTCAP) + difference = FILTCAP; + if (difference < -FILTCAP) + difference = -FILTCAP; + + if (diffg > FILTCAPG) + diffg = FILTCAPG; + if (diffg < -FILTCAPG) + diffg = -FILTCAPG; + + thiscol = g + (difference / 3); + thiscolg = g + (diffg / 3); + + if (thiscol < 0) + thiscol = 0; + if (thiscol > 1023) + thiscol = 1023; + + if (thiscolg < 0) + thiscolg = 0; + if (thiscolg > 1023) + thiscolg = 1023; + + voodoo->thefilter[g][h] = thiscol; + voodoo->thefilterg[g][h] = thiscolg; + } + + lined = g + 4; + if (lined > 1023) + lined = 1023; + voodoo->purpleline[g] = lined; + } +} + +static void voodoo_filterline(voodoo_t *voodoo, uint16_t *fil, int column, uint16_t *src, int line) +{ + int x; + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 4); + fil[x*3+2] = (((src[x] >> 11) & 31) << 5); + } + fil[x*3] = 0; + fil[x*3+1] = 0; + fil[x*3+2] = 0; + + /* filtering time */ + + for (x=1; xthefilter[fil[x*3]][fil[(x-1)*3]]; + fil[x*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[(x-1)*3+1]]; + fil[x*3+2] = voodoo->thefilter[fil[x*3+2]][fil[(x-1)*3+2]]; + } + for (x=1; xthefilter[fil[x*3]][fil[(x-1)*3]]; + fil[x*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[(x-1)*3+1]]; + fil[x*3+2] = voodoo->thefilter[fil[x*3+2]][fil[(x-1)*3+2]]; + } + for (x=1; xthefilter[fil[x*3]][fil[(x-1)*3]]; + fil[x*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[(x-1)*3+1]]; + fil[x*3+2] = voodoo->thefilter[fil[x*3+2]][fil[(x-1)*3+2]]; + } + + for (x=0; xthefilter[fil[x*3]][fil[(x+1)*3]]) >> 2; + fil[x*3+1] = (voodoo->thefilterg[fil[x*3+1]][fil[(x+1)*3+1]]) >> 2; + fil[x*3+2] = (voodoo->thefilter[fil[x*3+2]][fil[(x+1)*3+2]]) >> 2; + } + + /* lines */ + + if (line & 1) + { + for (x=0; xpurpleline[fil[x*3]]; + fil[x*3+2] = voodoo->purpleline[fil[x*3+2]]; + } + } +} + +void voodoo_callback(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line < voodoo->v_disp) + { + if (voodoo->dirty_line[voodoo->line]) + { + uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line + y_add])[32 + x_add]; + uint16_t *src = (uint16_t *)&voodoo->fb_mem[voodoo->front_offset + voodoo->line*voodoo->row_width]; + int x; + + voodoo->dirty_line[voodoo->line] = 0; + + if (voodoo->line < voodoo->dirty_line_low) + voodoo->dirty_line_low = voodoo->line; + if (voodoo->line > voodoo->dirty_line_high) + voodoo->dirty_line_high = voodoo->line; + + if (voodoo->scrfilter) + { + int j, offset; + uint16_t fil[(voodoo->h_disp + 1) * 3]; /* interleaved 24-bit RGB */ + + voodoo_filterline(voodoo, fil, voodoo->h_disp, src, voodoo->line); + + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = (voodoo->clutData256[fil[x*3]].b << 0 | voodoo->clutData256[fil[x*3+1]].g << 8 | voodoo->clutData256[fil[x*3+2]].r << 16); + } + } + else + { + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = voodoo->video_16to32[src[x]]; + } + } + } + } + } + if (voodoo->line == voodoo->v_disp) + { +// pclog("retrace %i %i %08x %i\n", voodoo->retrace_count, voodoo->swap_interval, voodoo->swap_offset, voodoo->swap_pending); + voodoo->retrace_count++; + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + voodoo->front_offset = voodoo->swap_offset; + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_set_event(voodoo->wake_fifo_thread); + voodoo->frame_count++; + } + voodoo->v_retrace = 1; + } + voodoo->line++; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line == voodoo->v_disp) + { + if (voodoo->dirty_line_high > voodoo->dirty_line_low) + svga_doblit(0, voodoo->v_disp, voodoo->h_disp, voodoo->v_disp, voodoo->svga); + if (voodoo->clutData_dirty) + { + voodoo->clutData_dirty = 0; + voodoo_calc_clutData(voodoo); + } + voodoo->dirty_line_high = -1; + voodoo->dirty_line_low = 2000; + } + } + + if (voodoo->line >= voodoo->v_total) + { + voodoo->line = 0; + voodoo->v_retrace = 0; + } + if (voodoo->line_time) + voodoo->timer_count += voodoo->line_time; + else + voodoo->timer_count += TIMER_USEC * 32; +} + +static void voodoo_add_status_info(char *s, int max_len, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + char temps[256]; + int pixel_count_current[2]; + int pixel_count_total; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + status_time = new_time; + + if (!status_diff) + status_diff = 1; + + svga_add_status_info(s, max_len, &voodoo->svga); + + pixel_count_current[0] = voodoo->pixel_count[0]; + pixel_count_current[1] = voodoo->pixel_count[1]; + pixel_count_total = (pixel_count_current[0] + pixel_count_current[1]) - (voodoo->pixel_count_old[0] + voodoo->pixel_count_old[1]); + sprintf(temps, "%f Mpixels/sec (%f)\n%f ktris/sec\n%f%% CPU (%f%% real)\n%d frames/sec (%i)\n%f%% CPU (%f%% real)\n%f%% CPU (%f%% real)\n"/*%d reads/sec\n%d write/sec\n%d tex/sec\n*/, + (double)pixel_count_total/1000000.0, + ((double)pixel_count_total/1000000.0) / ((double)voodoo_render_time[0] / status_diff), + (double)voodoo->tri_count/1000.0, ((double)voodoo_time * 100.0) / timer_freq, ((double)voodoo_time * 100.0) / status_diff, voodoo->frame_count, voodoo_recomp, + ((double)voodoo_render_time[0] * 100.0) / timer_freq, ((double)voodoo_render_time[0] * 100.0) / status_diff, + ((double)voodoo_render_time[1] * 100.0) / timer_freq, ((double)voodoo_render_time[1] * 100.0) / status_diff); + strncat(s, temps, max_len); + + voodoo->pixel_count_old[0] = pixel_count_current[0]; + voodoo->pixel_count_old[1] = pixel_count_current[1]; + voodoo->tri_count = voodoo->frame_count = 0; + voodoo->rd_count = voodoo->wr_count = voodoo->tex_count = 0; + voodoo_time = 0; + voodoo_render_time[0] = voodoo_render_time[1] = 0; + voodoo_recomp = 0; +} + +static void voodoo_speed_changed(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + voodoo_pixelclock_update(voodoo); +} + +void *voodoo_init() +{ + int c; + voodoo_t *voodoo = malloc(sizeof(voodoo_t)); + memset(voodoo, 0, sizeof(voodoo_t)); + + voodoo->bilinear_enabled = device_get_config_int("bilinear"); + voodoo->scrfilter = device_get_config_int("dacfilter"); + voodoo->texture_size = device_get_config_int("texture_memory"); + voodoo->texture_mask = (voodoo->texture_size << 20) - 1; + voodoo->fb_size = device_get_config_int("framebuffer_memory"); + voodoo->fb_mask = (voodoo->fb_size << 20) - 1; + voodoo->render_threads = device_get_config_int("render_threads"); + voodoo->odd_even_mask = voodoo->render_threads - 1; +#ifndef NO_CODEGEN + voodoo->use_recompiler = device_get_config_int("recompiler"); +#endif + voodoo_generate_filter(voodoo); /*generate filter lookup tables*/ + + pci_add(voodoo_pci_read, voodoo_pci_write, voodoo); + + mem_mapping_add(&voodoo->mapping, 0, 0, NULL, voodoo_readw, voodoo_readl, NULL, voodoo_writew, voodoo_writel, NULL, 0, voodoo); + + voodoo->fb_mem = malloc(4 * 1024 * 1024); + voodoo->tex_mem = malloc(voodoo->texture_size * 1024 * 1024); + voodoo->tex_mem_w = (uint16_t *)voodoo->tex_mem; + + timer_add(voodoo_callback, &voodoo->timer_count, TIMER_ALWAYS_ENABLED, voodoo); + + voodoo->svga = svga_get_pri(); + voodoo->fbiInit0 = 0; + + voodoo->wake_fifo_thread = thread_create_event(); + voodoo->wake_render_thread[0] = thread_create_event(); + voodoo->wake_render_thread[1] = thread_create_event(); + voodoo->wake_main_thread = thread_create_event(); + voodoo->fifo_not_full_event = thread_create_event(); + voodoo->render_not_full_event[0] = thread_create_event(); + voodoo->render_not_full_event[1] = thread_create_event(); + voodoo->fifo_thread = thread_create(fifo_thread, voodoo); + voodoo->render_thread[0] = thread_create(render_thread_1, voodoo); + if (voodoo->render_threads == 2) + voodoo->render_thread[1] = thread_create(render_thread_2, voodoo); + + for (c = 0; c < 0x100; c++) + { + rgb332[c].r = c & 0xe0; + rgb332[c].g = (c << 3) & 0xe0; + rgb332[c].b = (c << 6) & 0xc0; + rgb332[c].r = rgb332[c].r | (rgb332[c].r >> 3) | (rgb332[c].r >> 6); + rgb332[c].g = rgb332[c].g | (rgb332[c].g >> 3) | (rgb332[c].g >> 6); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 2); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 4); + rgb332[c].a = 0xff; + + ai44[c].a = (c & 0xf0) | ((c & 0xf0) >> 4); + ai44[c].r = (c & 0x0f) | ((c & 0x0f) << 4); + ai44[c].g = ai44[c].b = ai44[c].r; + } + + for (c = 0; c < 0x10000; c++) + { + rgb565[c].r = (c >> 8) & 0xf8; + rgb565[c].g = (c >> 3) & 0xfc; + rgb565[c].b = (c << 3) & 0xf8; + rgb565[c].r |= (rgb565[c].r >> 5); + rgb565[c].g |= (rgb565[c].g >> 6); + rgb565[c].b |= (rgb565[c].b >> 5); + rgb565[c].a = 0xff; + + argb1555[c].r = (c >> 7) & 0xf8; + argb1555[c].g = (c >> 2) & 0xf8; + argb1555[c].b = (c << 3) & 0xf8; + argb1555[c].r |= (argb1555[c].r >> 5); + argb1555[c].g |= (argb1555[c].g >> 5); + argb1555[c].b |= (argb1555[c].b >> 5); + argb1555[c].a = (c & 0x8000) ? 0xff : 0; + + argb4444[c].a = (c >> 8) & 0xf0; + argb4444[c].r = (c >> 4) & 0xf0; + argb4444[c].g = c & 0xf0; + argb4444[c].b = (c << 4) & 0xf0; + argb4444[c].a |= (argb4444[c].a >> 4); + argb4444[c].r |= (argb4444[c].r >> 4); + argb4444[c].g |= (argb4444[c].g >> 4); + argb4444[c].b |= (argb4444[c].b >> 4); + + ai88[c].a = (c >> 8); + ai88[c].r = c & 0xff; + ai88[c].g = c & 0xff; + ai88[c].b = c & 0xff; + } +#ifndef NO_CODEGEN + voodoo_codegen_init(voodoo); +#endif + return voodoo; +} + +void voodoo_close(void *p) +{ + FILE *f; + voodoo_t *voodoo = (voodoo_t *)p; +#ifndef RELEASE_BUILD + f = romfopen("texram.dmp", "wb"); + fwrite(voodoo->tex_mem, 2048*1024, 1, f); + fclose(f); +#endif + + thread_kill(voodoo->fifo_thread); + thread_kill(voodoo->render_thread[0]); + if (voodoo->render_threads == 2) + thread_kill(voodoo->render_thread[1]); + thread_destroy_event(voodoo->fifo_not_full_event); + thread_destroy_event(voodoo->wake_main_thread); + thread_destroy_event(voodoo->wake_fifo_thread); + thread_destroy_event(voodoo->wake_render_thread[0]); + thread_destroy_event(voodoo->wake_render_thread[1]); + thread_destroy_event(voodoo->render_not_full_event[0]); + thread_destroy_event(voodoo->render_not_full_event[1]); +#ifndef NO_CODEGEN + voodoo_codegen_close(voodoo); +#endif + free(voodoo->fb_mem); + free(voodoo->tex_mem); + free(voodoo); +} + +static device_config_t voodoo_config[] = +{ + { + .name = "framebuffer_memory", + .description = "Framebuffer memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "texture_memory", + .description = "Texture memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1", + .value = 1 + }, + { + .description = "2", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, +#endif + { + .type = -1 + } +}; + +device_t voodoo_device = +{ + "3DFX Voodoo Graphics", + 0, + voodoo_init, + voodoo_close, + NULL, + voodoo_speed_changed, + NULL, + voodoo_add_status_info, + voodoo_config +}; diff --git a/src/vid_voodoo.h b/src/vid_voodoo.h new file mode 100644 index 000000000..047978327 --- /dev/null +++ b/src/vid_voodoo.h @@ -0,0 +1 @@ +extern device_t voodoo_device; diff --git a/src/vid_voodoo_codegen_x86-64.h b/src/vid_voodoo_codegen_x86-64.h new file mode 100644 index 000000000..fcd84c433 --- /dev/null +++ b/src/vid_voodoo_codegen_x86-64.h @@ -0,0 +1,3720 @@ +/*Registers : + + alphaMode + fbzMode & 0x1f3fff + fbzColorPath +*/ + +#ifdef __linux__ +#include +#include +#endif +#if WIN64 +#define BITMAP windows_BITMAP +#include +#undef BITMAP +#endif + +#include + +#define BLOCK_NUM 8 +#define BLOCK_MASK (BLOCK_NUM-1) +#define BLOCK_SIZE 8192 + +typedef struct voodoo_x86_data_t +{ + uint8_t code_block[BLOCK_SIZE]; + int xdir; + uint32_t alphaMode; + uint32_t fbzMode; + uint32_t fogMode; + uint32_t fbzColorPath; + uint32_t textureMode; + uint32_t trexInit1; +} voodoo_x86_data_t; + +//static voodoo_x86_data_t voodoo_x86_data[2][BLOCK_NUM]; + +static int last_block[2] = {0, 0}; +static int next_block_to_write[2] = {0, 0}; + +#define addbyte(val) \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addword(val) \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addlong(val) \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addquad(val) \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + + +static __m128i xmm_01_w;// = 0x0001000100010001ull; +static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; +static __m128i xmm_ff_b;// = 0x00000000ffffffffull; + +static uint32_t zero = 0; +static double const_1_48 = (double)(1ull << 4); + +static __m128i alookup[257], aminuslookup[256]; +static __m128i minus_254;// = 0xff02ff02ff02ff02ull; +static __m128i bilinear_lookup[256*4]; + +static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) +{ + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; +// xmm_01_w = (__m128i)0x0001000100010001ull; +// xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; +// xmm_ff_b = (__m128i)0x00000000ffffffffull; + xmm_01_w = _mm_set_epi32(0, 0, 0x00010001, 0x00010001); + xmm_ff_w = _mm_set_epi32(0, 0, 0x00ff00ff, 0x00ff00ff); + xmm_ff_b = _mm_set_epi32(0, 0, 0, 0x00ffffff); + minus_254 = _mm_set_epi32(0, 0, 0xff02ff02, 0xff02ff02); +// *(uint64_t *)&const_1_48 = 0x45b0000000000000ull; +// block_pos = 0; +// voodoo_get_depth = &code_block[block_pos]; + /*W at (%esp+4) + Z at (%esp+12) + new_depth at (%esp+16)*/ +// if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depth_op == DEPTHOP_NEVER)) +// { +// addbyte(0xC3); /*RET*/ +// return; +// } + addbyte(0x55); /*PUSH RBP*/ + addbyte(0x57); /*PUSH RDI*/ + addbyte(0x56); /*PUSH RSI*/ + addbyte(0x53); /*PUSH RBX*/ + addbyte(0x41); /*PUSH R14*/ + addbyte(0x56); + addbyte(0x41); /*PUSH R15*/ + addbyte(0x57); + +#if WIN64 + addbyte(0x48); /*MOV RDI, RCX (voodoo_state)*/ + addbyte(0x89); + addbyte(0xcf); + addbyte(0x49); /*MOV R15, RDX (voodoo_params)*/ + addbyte(0x89); + addbyte(0xd7); + addbyte(0x4d); /*MOV R14, R9 (real_y)*/ + addbyte(0x89); + addbyte(0xce); +#else + addbyte(0x49); /*MOV R9, RCX (real_y)*/ + addbyte(0x89); + addbyte(0xc9); + addbyte(0x49); /*MOV R15, RSI (voodoo_state)*/ + addbyte(0x89); + addbyte(0xf7); +#endif + loop_jump_pos = block_pos; + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + addbyte(0x66); /*PXOR XMM2, XMM2*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xd2); + + if ((params->fbzMode & FBZ_W_BUFFER) || (params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0xb8); /*MOV new_depth, 0*/ + addlong(0); + addbyte(0x66); /*TEST w+4, 0xffff*/ + addbyte(0xf7); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addword(0xffff); + addbyte(0x75); /*JNZ got_depth*/ + depth_jump_pos = block_pos; + addbyte(0); +// addbyte(4+5+2+3+2+5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0x8b); /*MOV EDX, w*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xb8); /*MOV new_depth, 0xf001*/ + addlong(0xf001); + addbyte(0x89); /*MOV EBX, EDX*/ + addbyte(0xd3); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x74); /*JZ got_depth*/ + depth_jump_pos2 = block_pos; + addbyte(0); +// addbyte(5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0xb9); /*MOV ECX, 19*/ + addlong(19); + addbyte(0x0f); /*BSR EAX, EDX*/ + addbyte(0xbd); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 15*/ + addlong(15); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + addbyte(0x29); /*SUB EDX, EAX - EDX = exp*/ + addbyte(0xc2); + addbyte(0x29); /*SUB ECX, EDX*/ + addbyte(0xd1); + addbyte(0xc1); /*SHL EDX, 12*/ + addbyte(0xe2); + addbyte(12); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + addbyte(0x81); /*AND EBX, 0xfff - EBX = mant*/ + addbyte(0xe3); + addlong(0xfff); + addbyte(0x67); /*LEA EAX, 1[EDX, EBX]*/ + addbyte(0x8d); + addbyte(0x44); + addbyte(0x13); + addbyte(1); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w_depth)); + } + } + if (!(params->fbzMode & FBZ_W_BUFFER)) + { + addbyte(0x8b); /*MOV EAX, z*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + if (params->fbzMode & FBZ_DEPTH_BIAS) + { + addbyte(0x03); /*ADD EAX, params->zaColor[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + addbyte(0x25); /*AND EAX, 0xffff*/ + addlong(0xffff); + } + + addbyte(0x89); /*MOV state->new_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + + if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop != DEPTHOP_ALWAYS) && (depthop != DEPTHOP_NEVER)) + { + addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RCX, aux_mem[RDI]*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x0f); /*MOVZX EBX, [ECX+EBX*2]*/ + addbyte(0xb7); + addbyte(0x1c); + addbyte(0x59); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + if (depthop == DEPTHOP_LESSTHAN) + { + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_EQUAL) + { + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_LESSTHANEQUAL) + { + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHAN) + { + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_NOTEQUAL) + { + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHANEQUAL) + { + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + z_skip_pos = block_pos; + addlong(0); + } + else + fatal("Bad depth_op\n"); + } + else if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop == DEPTHOP_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + /*XMM0 = colour*/ + /*XMM2 = 0 (for unpacking*/ + + /*EDI = state, ESI = params*/ + + if (params->textureMode & 1) + { + addbyte(0x48); /*MOV RBX, state->tmu0_s*/ + addbyte(0x8b); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x48); /*MOV RAX, (1 << 48)*/ + addbyte(0xb8); + addquad(1ULL << 48); + addbyte(0x48); /*XOR RDX, RDX*/ + addbyte(0x31); + addbyte(0xd2); + addbyte(0x48); /*MOV RCX, state->tmu0_t*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x48); /*CMP state->tmu_w, 0*/ + addbyte(0x83); + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7); + addbyte(0x48); /*IDIV state->tmu_w*/ + addbyte(0xf7); + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x48); /*SAR RBX, 14*/ + addbyte(0xc1); + addbyte(0xfb); + addbyte(14); + addbyte(0x48); /*SAR RCX, 14*/ + addbyte(0xc1); + addbyte(0xf9); + addbyte(14); + addbyte(0x48); /*IMUL RBX, RAX*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0xd8); + addbyte(0x48); /*IMUL RCX, RAX*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0xc8); + addbyte(0x48); /*SAR RBX, 30*/ + addbyte(0xc1); + addbyte(0xfb); + addbyte(30); + addbyte(0x48); /*SAR RCX, 30*/ + addbyte(0xc1); + addbyte(0xf9); + addbyte(30); + addbyte(0x48); /*BSR EDX, RAX*/ + addbyte(0x0f); + addbyte(0xbd); + addbyte(0xd0); + addbyte(0x48); /*SHL RAX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + addbyte(0x89); /*MOV state->tex_t, ECX*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV ECX, EDX*/ + addbyte(0xd1); + addbyte(0x83); /*SUB EDX, 19*/ + addbyte(0xea); + addbyte(19); + addbyte(0x48); /*SHR RAX, CL*/ + addbyte(0xd3); + addbyte(0xe8); + addbyte(0xc1); /*SHL EDX, 8*/ + addbyte(0xe2); + addbyte(8); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0x89); /*MOV state->tex_s, EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x0f); /*MOVZX EAX, logtable[RAX]*/ + addbyte(0xb6); + addbyte(0x80); + addlong((uint32_t)logtable); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0x03); /*ADD EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu[0].lod)); + addbyte(0x3b); /*CMP EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x0f); /*CMOVL EAX, state->lod_min*/ + addbyte(0x4c); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x3b); /*CMP EAX, state->lod_max*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max)); + addbyte(0x0f); /*CMOVNL EAX, state->lod_max*/ + addbyte(0x4d); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max)); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + else + { + addbyte(0x48); /*MOV RAX, state->tmu0_s*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x48); /*MOV RCX, state->tmu0_t*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x48); /*SHR RAX, 28*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(28); + addbyte(0x8b); /*MOV EBX, state->lod_min*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x48); /*SHR RCX, 28*/ + addbyte(0xc1); + addbyte(0xe9); + addbyte(28); + addbyte(0x48); /*MOV state->tex_s, RAX*/ + addbyte(0x89); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x48); /*MOV state->tex_t, RCX*/ + addbyte(0x89); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV state->lod, EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod)); + } + + + if (voodoo->trexInit1 & (1 << 18)) + { + addbyte(0xb8); /*MOV EAX, 0x000001*/ + addlong(0x000001); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + } + else if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (voodoo->bilinear_enabled && (params->textureMode & 6)) + { + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xbd); /*MOV EBP, 1*/ + addlong(1); + addbyte(0x8a); /*MOV DL, params->tex_shift[RSI+ECX*4]*/ + addbyte(0x94); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0xd3); /*SHL EBP, CL*/ + addbyte(0xe5); + addbyte(0x8b); /*MOV EAX, state->tex_s[RDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHL EBP, 3*/ + addbyte(0xe5); + addbyte(3); + addbyte(0x8b); /*MOV EBX, state->tex_t[RDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x29); /*SUB EAX, EBP*/ + addbyte(0xe8); + addbyte(0x29); /*SUB EBX, EBP*/ + addbyte(0xeb); + addbyte(0xd3); /*SAR EAX, CL*/ + addbyte(0xf8); + addbyte(0xd3); /*SAR EBX, CL*/ + addbyte(0xfb); + addbyte(0x89); /*MOV EBP, EAX*/ + addbyte(0xc5); + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + addbyte(0x83); /*AND EBP, 0xf*/ + addbyte(0xe5); + addbyte(0xf); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SAR EAX, 4*/ + addbyte(0xf8); + addbyte(4); + addbyte(0x81); /*AND ECX, 0xf0*/ + addbyte(0xe1); + addlong(0xf0); + addbyte(0xc1); /*SAR EBX, 4*/ + addbyte(0xfb); + addbyte(4); + addbyte(0x09); /*OR EBP, ECX*/ + addbyte(0xcd); + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xc1); /*SHL EBP, 6*/ + addbyte(0xe5); + addbyte(6); + /*EAX = S, EBX = T, ECX = LOD, EDX = tex_shift, ESI=params, EDI=state, EBP = bilinear shift*/ + addbyte(0x48); /*LEA RSI, [RSI+RCX*4]*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x8e); + addbyte(0x89); /*MOV ebp_store, EBP*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x48); /*MOV RBP, state->tex[RDI+RCX*8]*/ + addbyte(0x8b); + addbyte(0xac); + addbyte(0xcf); + addlong(offsetof(voodoo_state_t, tex)); + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + if (!state->clamp_s) + { + addbyte(0x23); /*AND EAX, params->tex_w_mask[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + } + addbyte(0x83); /*ADD EDX, 1*/ + addbyte(0xc2); + addbyte(1); + if (state->clamp_t) + { + addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x48); + addbyte(0x14); + addbyte(0x25); + addlong(&zero); + addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x0f); /*CMOVA EDX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x85); /*TEST EBX,EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1c); + addbyte(0x25); + addlong(&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x0f); /*CMOVA EBX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + } + else + { + addbyte(0x23); /*AND EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x23); /*AND EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + } + /*EAX = S, EBX = T0, EDX = T1*/ + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0xd3); /*SHL EDX, CL*/ + addbyte(0xe2); + if (state->tformat & 8) + { + addbyte(0x48); /*LEA RBX,[RBP+RBX*2]*/ + addbyte(0x8d); + addbyte(0x5c); + addbyte(0x5d); + addbyte(0); + addbyte(0x48); /*LEA RDX,[RBP+RDX*2]*/ + addbyte(0x8d); + addbyte(0x54); + addbyte(0x55); + addbyte(0); + } + else + { + addbyte(0x48); /*ADD RBX, RBP*/ + addbyte(0x01); + addbyte(0xeb); + addbyte(0x48); /*ADD RDX, RBP*/ + addbyte(0x01); + addbyte(0xea); + } + if (state->clamp_s) + { + addbyte(0x8b); /*MOV EBP, params->tex_w_mask[ESI]*/ + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x8b); /*MOV ebp_store2, RSI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x04); + addbyte(0x25); + addlong(&zero); + addbyte(0x78); /*JS + - clamp on 0*/ + addbyte(2+3+2+ ((state->tformat & 8) ? (3+3+2) : (4+4+2))); + addbyte(0x3b); /*CMP EAX, EBP*/ + addbyte(0xc5); + addbyte(0x0f); /*CMOVAE EAX, EBP*/ + addbyte(0x43); + addbyte(0xc5); + addbyte(0x73); /*JAE + - clamp on +*/ + addbyte((state->tformat & 8) ? (3+3+2) : (4+4+2)); + } + else + { + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI] - is S at texture edge (ie will wrap/clamp)?*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + addbyte(0x8b); /*MOV ebp_store2, ESI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x74); /*JE +*/ + addbyte((state->tformat & 8) ? (3+3+2) : (4+4+2)); + } + + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV EDX,[RDX+RAX*2]*/ + addbyte(0x14); + addbyte(0x42); + addbyte(0x8b); /*MOV EAX,[RBX+RAX*2]*/ + addbyte(0x04); + addbyte(0x43); + } + else + { + addbyte(0x0f); /*MOVZX EDX,W[RDX+RAX]*/ + addbyte(0xb7); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,W[RBX+RAX]*/ + addbyte(0xb7); + addbyte(0x04); + addbyte(0x03); + } + + if (state->clamp_s) + { + addbyte(0xeb); /*JMP +*/ + addbyte((state->tformat & 8) ? (3+4+3+3+4+3) : (4+4+2+2)); + + /*S clamped - the two S coordinates are the same*/ + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV ECX, [RDX+RAX*2]*/ + addbyte(0x0c); + addbyte(0x42); + addbyte(0x8b); /*MOV EDX, [RDX+RAX*2-2]*/ + addbyte(0x54); + addbyte(0x42); + addbyte(-2); + addbyte(0x66); /*MOV DX, CX*/ + addbyte(0x89); + addbyte(0xca); + addbyte(0x8b); /*MOV ECX, [RBX+RAX*2]*/ + addbyte(0x0c); + addbyte(0x43); + addbyte(0x8b); /*MOV EAX, [RBX+RAX*2-2]*/ + addbyte(0x44); + addbyte(0x43); + addbyte(-2); + addbyte(0x66); /*MOV AX, CX*/ + addbyte(0x89); + addbyte(0xc8); + } + else + { + addbyte(0x0f); /*MOVZX EDX,W[RDX+RAX]*/ + addbyte(0xb7); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,W[RBX+RAX]*/ + addbyte(0xb7); + addbyte(0x04); + addbyte(0x03); + addbyte(0x88); /*MOV DH, DL*/ + addbyte(0xd6); + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + } + } + else + { + addbyte(0xeb); /*JMP +*/ + addbyte((state->tformat & 8) ? (3+3+3+3+3+3) : (2+2+4+4+2+2)); + + /*S wrapped - the two S coordinates are not contiguous*/ + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV ECX, [RDX+RAX*2]*/ + addbyte(0x0c); + addbyte(0x42); + addbyte(0x8b); /*MOV EDX, [RDX-2]*/ + addbyte(0x52); + addbyte(-2); + addbyte(0x66); /*MOV DX, CX*/ + addbyte(0x89); + addbyte(0xca); + addbyte(0x8b); /*MOV ECX, [RBX+RAX*2]*/ + addbyte(0x0c); + addbyte(0x43); + addbyte(0x8b); /*MOV EAX, [RBX-2]*/ + addbyte(0x43); + addbyte(-2); + addbyte(0x66); /*MOV AX, CX*/ + addbyte(0x89); + addbyte(0xc8); + } + else + { + addbyte(0x8a); /*MOV CL, [RDX]*/ + addbyte(0x0a); + addbyte(0x8a); /*MOV CH, [RBX]*/ + addbyte(0x2b); + addbyte(0x0f); /*MOVZX EDX,B[RDX+RAX]*/ + addbyte(0xb6); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,B[RBX+RAX]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x03); + addbyte(0x88); /*MOV DH, CL*/ + addbyte(0xce); + addbyte(0x88); /*MOV AH, CH*/ + addbyte(0xec); + } + } + + addbyte(0x49); /*MOV R8, bilinear_lookup*/ + addbyte(0xb8); + addquad(bilinear_lookup); + addbyte(0x4c); /*ADD RSI, R8*/ + addbyte(0x01); + addbyte(0xc6); + + switch (state->tformat) + { + case TEX_RGB332: + addbyte(0x49); /*MOV R8, rgb332*/ + addbyte(0xb8); + addquad(rgb332); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+ECX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_Y4I2Q2: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_A8: + addbyte(0x66); /*MOVZX CX, AH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*MOVZX AX, AL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xc0); + addbyte(0x66); /*IMUL CX, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*IMUL AX, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x06); + addbyte(0x66); /*MOVZX BX, DH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xde); + addbyte(0x66); /*MOVZX DX, DL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xd2); + addbyte(0x66); /*ADD AX, CX*/ + addbyte(0x01); + addbyte(0xc8); + addbyte(0x66); /*IMUL BX, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x5e); + addbyte(0x30); + addbyte(0x66); /*IMUL DX, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x56); + addbyte(0x20); + addbyte(0x66); /*ADD AX, BX*/ + addbyte(0x01); + addbyte(0xd8); + addbyte(0x66); /*ADD AX, DX*/ + addbyte(0x01); + addbyte(0xd0); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x66); /*MOV BX, AX*/ + addbyte(0x89); + addbyte(0xc3); + addbyte(0x0f); /*BSWAP EAX*/ + addbyte(0xc8); + addbyte(0x66); /*MOV AX, BX*/ + addbyte(0x89); + addbyte(0xd8); + break; + + case TEX_I8: + addbyte(0x66); /*MOVZX CX, AH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*MOVZX AX, AL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xc0); + addbyte(0x66); /*IMUL CX, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*IMUL AX, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x06); + addbyte(0x66); /*MOVZX BX, DH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xde); + addbyte(0x66); /*MOVZX DX, DL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xd2); + addbyte(0x66); /*ADD AX, CX*/ + addbyte(0x01); + addbyte(0xc8); + addbyte(0x66); /*IMUL BX, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x5e); + addbyte(0x30); + addbyte(0x66); /*IMUL DX, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x56); + addbyte(0x20); + addbyte(0x66); /*ADD AX, BX*/ + addbyte(0x01); + addbyte(0xd8); + addbyte(0x66); /*ADD AX, DX*/ + addbyte(0x01); + addbyte(0xd0); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_AI8: + addbyte(0x49); /*MOV R8, ai44*/ + addbyte(0xb8); + addquad(ai44); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+ECX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_PAL8: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_R5G6B5: + addbyte(0x49); /*MOV R8, rgb565*/ + addbyte(0xb8); + addquad(rgb565); + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x66); /*MOVD XMM1, [R8+RAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+EDX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x90); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_ARGB1555: + addbyte(0x49); /*MOV R8, argb1555*/ + addbyte(0xb8); + addquad(argb1555); + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x66); /*MOVD XMM1, [R8+RAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+EDX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x90); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_ARGB4444: + addbyte(0x49); /*MOV R8, argb4444*/ + addbyte(0xb8); + addquad(argb4444); + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x66); /*MOVD XMM1, [R8+RAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+EDX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x90); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_A8I8: + addbyte(0x49); /*MOV R8, ai88*/ + addbyte(0xb8); + addquad(ai88); + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x66); /*MOVD XMM1, [R8+RAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+EDX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x90); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_APAL88: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*PINSRW XMM0, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc1); + addbyte(3); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PINSRW XMM1, EAX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc8); + addbyte(3); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PINSRW XMM3, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xd9); + addbyte(3); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PINSR1 XMM1, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + + addbyte(0xc9); + addbyte(3); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } + + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + } + else + { + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0x8a); /*MOV DL, params->tex_shift[RSI+RCX*4]*/ + addbyte(0x94); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0x48); /*MOV RBP, state->tex[RDI+RCX*8]*/ + addbyte(0x8b); + addbyte(0xac); + addbyte(0xcf); + addlong(offsetof(voodoo_state_t, tex)); + addbyte(0x80); /*ADD CL, 4*/ + addbyte(0xc1); + addbyte(4); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0xd3); /*SHR EAX, CL*/ + addbyte(0xe8); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + if (state->clamp_s) + { + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x04); + addbyte(0x25); + addlong(&zero); + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + addbyte(0x0f); /*CMOVAE EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + + } + else + { + addbyte(0x23); /*AND EAX, params->tex_w_mask-0x10[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + } + if (state->clamp_t) + { + addbyte(0x85); /*TEST EBX, EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1c); + addbyte(0x25); + addlong(&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + addbyte(0x0f); /*CMOVAE EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + } + else + { + addbyte(0x23); /*AND EBX, params->tex_h_mask-0x10[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + } + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0x01); /*ADD EBX, EAX*/ + addbyte(0xc3); + + if (state->tformat & 8) + { + addbyte(0x0f); /*MOVZX EAX,W[EBP+EBX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x5d); + addbyte(0); + } + else + { + addbyte(0x0f); /*MOVZX EAX,B[EBP+EBX]*/ + addbyte(0xb6); + addbyte(0x44); + addbyte(0x1d); + addbyte(0); + } + + switch (state->tformat) + { + case TEX_RGB332: + addbyte(0x49); /*MOV R8, rgb332*/ + addbyte(0xb8); + addquad(rgb332); + addbyte(0x41); /*MOV EAX, [R8+EAX*4]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0x80); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_Y4I2Q2: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_A8: + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0x66); /*MOV BX, AX*/ + addbyte(0x89); + addbyte(0xc3); + addbyte(0x0f); /*BSWAP EAX*/ + addbyte(0xc8); + addbyte(0x66); /*MOV AX, BX*/ + addbyte(0x89); + addbyte(0xd8); + break; + + case TEX_I8: + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_AI8: + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*AND EAX, 0x0f*/ + addbyte(0xe0); + addbyte(0x0f); + addbyte(0x81); /*AND EBX, 0xf0*/ + addbyte(0xe3); + addlong(0xf0); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SHR EDX, 4*/ + addbyte(0xe2); + addbyte(4); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + addbyte(0x09); /*OR EBX, EDX*/ + addbyte(0xd3); + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0xc1); /*SHL EBX, 24*/ + addbyte(0xe3); + addbyte(24); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + break; + + case TEX_PAL8: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_R5G6B5: + addbyte(0x49); /*MOV R8, rgb565*/ + addbyte(0xb8); + addquad(rgb565); + addbyte(0x41); /*MOV EAX, [R8+EAX*4]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0x80); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_ARGB1555: + addbyte(0x49); /*MOV R8, argb1555*/ + addbyte(0xb8); + addquad(argb1555); + addbyte(0x41); /*MOV EAX, [R8+EAX*4]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0x80); + break; + + case TEX_ARGB4444: + addbyte(0x49); /*MOV R8, argb4444*/ + addbyte(0xb8); + addquad(argb4444); + addbyte(0x41); /*MOV EAX, [R8+EAX*4]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0x80); + break; + + case TEX_A8I8: + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0xc1); /*SHL EAX, 16*/ + addbyte(0xe0); + addbyte(16); + addbyte(0x88); /*MOV AL, BL*/ + addbyte(0xd8); + addbyte(0x88); /*MOV AH, BL*/ + addbyte(0xdc); + break; + + case TEX_APAL88: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x25); /*AND EAX, 0x000000ff*/ + addlong(0x000000ff); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); + addbyte(0xc1); /*SHL EBX, 16*/ + addbyte(0xe3); + addbyte(16); + addbyte(0x81); /*AND EBX, 0xff000000*/ + addbyte(0xe3); + addlong(0xff000000); + addbyte(0x25); /*AND EAX, 0x00ffffff*/ + addlong(0x00ffffff); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } + } + if ((params->fbzMode & FBZ_CHROMAKEY)) + { + addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, chromaKey)); + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x81); /*AND EBX, 0xffffff*/ + addbyte(0xe3); + addlong(0xffffff); + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + chroma_skip_pos = block_pos; + addlong(0); + } + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + /*EBX = a_other*/ + switch (a_sel) + { + case A_SEL_ITER_A: + addbyte(0x8b); /*MOV EBX, state->ia*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1); /*SAR EBX, 12*/ + addbyte(0xfb); + addbyte(12); + addbyte(0x0f); /*CMOVS EBX, EAX*/ + addbyte(0x48); + addbyte(0xd8); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVA EBX, EDX*/ + addbyte(0x47); + addbyte(0xda); + break; + case A_SEL_TEX: + addbyte(0x8b); /*MOV EBX, state->tex_a*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + case A_SEL_COLOR1: + addbyte(0x0f); /*MOVZX EBX, params->color1+3*/ + addbyte(0xb6); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, color1)+3); + break; + default: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + } + /*ECX = a_local*/ + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + if (a_sel == A_SEL_ITER_A) + { + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + } + else + { + addbyte(0x8b); /*MOV ECX, state->ia*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1);/*SAR ECX, 12*/ + addbyte(0xf9); + addbyte(12); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + } + break; + case CCA_LOCALSELECT_COLOR0: + addbyte(0x0f); /*MOVZX ECX, params->color0+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)+3); + break; + case CCA_LOCALSELECT_ITER_Z: + addbyte(0x8b); /*MOV ECX, state->z*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, z)); + if (a_sel != A_SEL_ITER_A) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + } + addbyte(0xc1);/*SAR ECX, 20*/ + addbyte(0xf9); + addbyte(20); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + break; + + default: + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + break; + } + + if (cca_zero_other) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + } + + if (cca_sub_clocal) + { + addbyte(0x29); /*SUB EDX, ECX*/ + addbyte(0xca); + } + } + + if (cc_sub_clocal || cc_mselect == 1 || cc_add == 1) + { + /*XMM1 = local*/ + if (!cc_localselect_override) + { + if (cc_localselect) + { + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + } + else + { + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + } + else + { + addbyte(0xf6); /*TEST state->tex_a, 0x80*/ + addbyte(0x87); + addbyte(0x23); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0x80); + addbyte(0x74);/*JZ !cc_localselect*/ + addbyte(8+2); + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + /*JMP +*/ + /*!cc_localselect:*/ + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + } + if (!cc_zero_other) + { + if (_rgb_sel == CC_LOCALSELECT_ITER_RGB) + { + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + else if (_rgb_sel == CC_LOCALSELECT_TEX) + { +#if 0 + addbyte(0xf3); /*MOVDQU XMM0, state->tex_b*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); +#endif + } + else if (_rgb_sel == CC_LOCALSELECT_COLOR1) + { + addbyte(0x66); /*MOVD XMM0, params->color1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + } + else + { + /*MOVD XMM0, src_r*/ + } + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + else + { + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + if (!(cca_mselect == 0 && cca_reverse_blend == 0)) + { + switch (cca_mselect) + { + case CCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_AOTHER: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case CCA_MSELECT_ALOCAL2: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_TEX: + addbyte(0x0f); /*MOVZX EAX, state->tex_a*/ + addbyte(0xb6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + + case CCA_MSELECT_ZERO: + default: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + } + if (!cca_reverse_blend) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EDX, EAX*/ + addbyte(0xaf); + addbyte(0xd0); + addbyte(0xc1); /*SHR EDX, 8*/ + addbyte(0xea); + addbyte(8); + } + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) + { + /*Copy a_other to XMM3 before it gets modified*/ + addbyte(0x66); /*MOVD XMM3, EDX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xda); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + } + + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x01); /*ADD EDX, ECX*/ + addbyte(0xca); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x85); /*TEST EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*CMOVS EDX, EAX*/ + addbyte(0x48); + addbyte(0xd0); + addbyte(0xb8); /*MOV EAX, 0xff*/ + addlong(0xff); + addbyte(0x81); /*CMP EDX, 0xff*/ + addbyte(0xfa); + addlong(0xff); + addbyte(0x0f); /*CMOVA EDX, EAX*/ + addbyte(0x47); + addbyte(0xd0); + if (cca_invert_output) + { + addbyte(0x81); /*XOR EDX, 0xff*/ + addbyte(0xf2); + addlong(0xff); + } + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0)) + { + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + case CC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + break; + case CC_MSELECT_ALOCAL: + addbyte(0x66); /*MOVD XMM3, ECX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd9); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + break; + case CC_MSELECT_AOTHER: + /*Handled above*/ + break; + case CC_MSELECT_TEX: + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 1*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(1); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(2); + break; + default: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + } + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + if (!cc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x1c); + addbyte(0x25); + addlong(&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x1c); + addbyte(0x25); + addlong(&xmm_01_w); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM4, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xe3); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc4); + addbyte(0x66); /*PSRLD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + } + + if (cc_add == 1) + { + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + if (cc_invert_output) + { + addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x04); + addbyte(0x25); + addlong(&xmm_ff_b); + } + + if (params->fogMode & FOG_ENABLE) + { + if (params->fogMode & FOG_CONSTANT) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PADDUSB XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xdc); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + + if (!(params->fogMode & FOG_ADD)) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + else + { + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + } + + if (!(params->fogMode & FOG_MULT)) + { + addbyte(0x66); /*PSUBW XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xd8); + } + + /*Divide by 2 to prevent overflow on multiply*/ + addbyte(0x66); /*PSRAW XMM3, 1*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(1); + + if (params->fogMode & FOG_Z) + { + addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + } + else if (params->fogMode & FOG_ALPHA) + { + addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); + } + else + { + addbyte(0x8b); /*MOV EBX, state->w_depth[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, w_depth)); + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + addbyte(0xc1); /*SHR EBX, 10*/ + addbyte(0xeb); + addbyte(10); + addbyte(0xc1); /*SHR EAX, 2*/ + addbyte(0xe8); + addbyte(2); + addbyte(0x83); /*AND EBX, 0x3f*/ + addbyte(0xe3); + addbyte(0x3f); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0xf6); /*MUL params->fogTable+1[ESI+EBX*2]*/ + addbyte(0xa4); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)+1); + addbyte(0x0f); /*MOVZX EBX, params->fogTable[ESI+EBX*2]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)); + addbyte(0xc1); /*SHR EAX, 10*/ + addbyte(0xe8); + addbyte(10); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x01); /*ADD EAX, EAX*/ + addbyte(0xc0); + + addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x1c); + addbyte(0xc5); + addlong(((uintptr_t)alookup) + 16); + addbyte(0x66); /*PSRAW XMM3, 7*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(7); + + if (params->fogMode & FOG_MULT) + { + addbyte(0xf3); /*MOV XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + } + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + } + + if ((params->alphaMode & 1) && (alpha_func != AFUNC_NEVER) && (alpha_func != AFUNC_ALWAYS)) + { + addbyte(0x0f); /*MOVZX ECX, params->alphaMode+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, alphaMode) + 3); + addbyte(0x39); /*CMP EDX, ECX*/ + addbyte(0xca); + + switch (alpha_func) + { + case AFUNC_LESSTHAN: + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_EQUAL: + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_LESSTHANEQUAL: + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHAN: + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_NOTEQUAL: + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHANEQUAL: + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + a_skip_pos = block_pos; + addlong(0); + break; + } + } + else if ((params->alphaMode & 1) && (alpha_func == AFUNC_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + if (params->alphaMode & (1 << 4)) + { + addbyte(0x49); /*MOV R8, rgb565*/ + addbyte(0xb8); + addquad(rgb565); + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RBP, fb_mem*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x01); /*ADD EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*MOVZX EAX, [RBP+RAX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x45); + addbyte(0); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, rgb565[EAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x24); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOV XMM6, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xf4); + + switch (dest_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe0); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2c); + addbyte(0x25); + addlong(&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe5); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASATURATE: + addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(&minus_254); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + } + + switch (src_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong(alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM0, XMM6*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc6); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong(aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2c); + addbyte(0x25); + addlong(&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM6*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xee); + addbyte(0x66); /*PMULLW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc5); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ACOLORBEFOREFOG: + break; + } + + addbyte(0x66); /*PADDW XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc4); + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + + if (params->fbzMode & FBZ_RGB_WMASK) + { + if (dither) + { + addbyte(0x49); /*MOV R8, dither_rb*/ + addbyte(0xb8); + addquad(dither2x2 ? dither_rb2x2 : dither_rb); + addbyte(0x4c); /*MOV ESI, real_y (R14)*/ + addbyte(0x89); + addbyte(0xf6); + addbyte(0x0f); /*MOVZX EBX, AH*/ /*G*/ + addbyte(0xb6); + addbyte(0xdc); + if (dither2x2) + { + addbyte(0x83); /*AND EDX, 1*/ + addbyte(0xe2); + addbyte(1); + addbyte(0x83); /*AND ESI, 1*/ + addbyte(0xe6); + addbyte(1); + addbyte(0xc1); /*SHL EBX, 2*/ + addbyte(0xe3); + addbyte(2); + } + else + { + addbyte(0x83); /*AND EDX, 3*/ + addbyte(0xe2); + addbyte(3); + addbyte(0x83); /*AND ESI, 3*/ + addbyte(0xe6); + addbyte(3); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + } + addbyte(0x0f); /*MOVZX ECX, AL*/ /*R*/ + addbyte(0xb6); + addbyte(0xc8); + if (dither2x2) + { + addbyte(0xc1); /*SHR EAX, 14*/ + addbyte(0xe8); + addbyte(14); + addbyte(0x8d); /*LEA ESI, RDX+RSI*2*/ + addbyte(0x34); + addbyte(0x72); + } + else + { + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x8d); /*LEA ESI, RDX+RSI*4*/ + addbyte(0x34); + addbyte(0xb2); + } + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x4c); /*ADD RSI, R8*/ + addbyte(0x01); + addbyte(0xc6); + if (dither2x2) + { + addbyte(0xc1); /*SHL ECX, 2*/ + addbyte(0xe1); + addbyte(2); + addbyte(0x25); /*AND EAX, 0x3fc*/ /*B*/ + addlong(0x3fc); + } + else + { + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0x25); /*AND EAX, 0xff0*/ /*B*/ + addlong(0xff0); + } + addbyte(0x0f); /*MOVZX EBX, dither_g[EBX+ESI]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x1e); + addlong(dither2x2 ? ((uintptr_t)dither_g2x2 - (uintptr_t)dither_rb2x2) : ((uintptr_t)dither_g - (uintptr_t)dither_rb)); + addbyte(0x0f); /*MOVZX ECX, dither_rb[RCX+RSI]*/ + addbyte(0xb6); + addbyte(0x0c); + addbyte(0x0e); + addbyte(0x0f); /*MOVZX EAX, dither_rb[RAX+RSI]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x06); + addbyte(0xc1); /*SHL EBX, 5*/ + addbyte(0xe3); + addbyte(5); + addbyte(0xc1); /*SHL EAX, 11*/ + addbyte(0xe0); + addbyte(11); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + else + { + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0xc1); /*SHR EAX, 3*/ + addbyte(0xe8); + addbyte(3); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0xc1); /*SHL ECX, 3*/ + addbyte(0xe1); + addbyte(3); + addbyte(0x81); /*AND EAX, 0x001f*/ + addbyte(0xe0); + addlong(0x001f); + addbyte(0x81); /*AND EBX, 0xf800*/ + addbyte(0xe3); + addlong(0xf800); + addbyte(0x81); /*AND ECX, 0x07e0*/ + addbyte(0xe1); + addlong(0x07e0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + addbyte(0x48); /*MOV RSI, fb_mem*/ + addbyte(0x8b); + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (params->fbzMode & FBZ_DEPTH_WMASK) + { + addbyte(0x66); /*MOV AX, new_depth*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + addbyte(0x48); /*MOV RSI, aux_mem*/ + addbyte(0x8b); + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (z_skip_pos) + *(uint32_t *)&code_block[z_skip_pos] = (block_pos - z_skip_pos) - 4; + if (a_skip_pos) + *(uint32_t *)&code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; + if (chroma_skip_pos) + *(uint32_t *)&code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; + + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + + addbyte(0xf3); /*MOVDQU XMM1, state->ib[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVDQU XMM3, state->tmu0_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xf3); /*MOVDQU XMM0, params->dBdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dBdX)); + addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dZdX)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[0].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[0].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[0].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[0].dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfe); + addbyte(0xc8); + } + else + { + addbyte(0x66); /*PSUBD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfa); + addbyte(0xc8); + } + + addbyte(0xf3); /*MOVQ XMM0, state->w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xf3); /*MOVDQU state->ib, XMM1*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVQ XMM7, params->dWdX*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xbe); + addlong(offsetof(voodoo_params_t, dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + addbyte(0x66); /*PADDQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xc7); + addbyte(0x01); /*ADD state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + addbyte(0x66); /*PSUBQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xc7); + addbyte(0x29); /*SUB state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + + addbyte(0xf3); /*MOVDQU state->tmu0_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x66); /*MOVQ state->tmu0_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x66); /*MOVQ state->w, XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, pixel_count)); + addbyte(1); + + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + if (state->xdir > 0) + { + addbyte(0x83); /*ADD state->x[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + else + { + addbyte(0x83); /*SUB state->x[EDI], 1*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + + addbyte(0x3b); /*CMP EAX, state->x2[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x2)); + addbyte(0x0f); /*JNZ loop_jump_pos*/ + addbyte(0x85); + addlong(loop_jump_pos - (block_pos + 4)); + + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x5b); /*POP RBX*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5d); /*POP RBP*/ + + addbyte(0xC3); /*RET*/ +} +static int voodoo_recomp = 0; +static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) +{ + int c; + int b = last_block[odd_even]; + voodoo_x86_data_t *voodoo_x86_data = voodoo->codegen_data; + voodoo_x86_data_t *data; + + for (c = 0; c < 8; c++) + { + data = &voodoo_x86_data[odd_even + c*2]; //&voodoo_x86_data[odd_even][b]; + + if (state->xdir == data->xdir && + params->alphaMode == data->alphaMode && + params->fbzMode == data->fbzMode && + params->fogMode == data->fogMode && + params->fbzColorPath == data->fbzColorPath && + (voodoo->trexInit1 & (1 << 18)) == data->trexInit1 && + params->textureMode == data->textureMode) + { + last_block[odd_even] = b; + return data->code_block; + } + + b = (b + 1) & 7; + } +voodoo_recomp++; + data = &voodoo_x86_data[odd_even + next_block_to_write[odd_even]*2]; +// code_block = data->code_block; + + voodoo_generate(data->code_block, voodoo, params, state, depth_op); + + data->xdir = state->xdir; + data->alphaMode = params->alphaMode; + data->fbzMode = params->fbzMode; + data->fogMode = params->fogMode; + data->fbzColorPath = params->fbzColorPath; + data->trexInit1 = voodoo->trexInit1 & (1 << 18); + data->textureMode = params->textureMode; + + next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; + + return data->code_block; +} + +static void voodoo_codegen_init(voodoo_t *voodoo) +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if WIN64 + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2); +#endif + +#ifdef __linux__ + start = (void *)((long)voodoo->codegen_data & pagemask); + len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif + + for (c = 0; c < 256; c++) + { + int d[4]; + int _ds = c & 0xf; + int dt = c >> 4; + + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); + aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); + + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + + bilinear_lookup[c*4] = _mm_set_epi32(0, 0, d[0] | (d[0] << 16), d[0] | (d[0] << 16)); + bilinear_lookup[c*4 + 1] = _mm_set_epi32(0, 0, d[1] | (d[1] << 16), d[1] | (d[1] << 16)); + bilinear_lookup[c*4 + 2] = _mm_set_epi32(0, 0, d[2] | (d[2] << 16), d[2] | (d[2] << 16)); + bilinear_lookup[c*4 + 3] = _mm_set_epi32(0, 0, d[3] | (d[3] << 16), d[3] | (d[3] << 16)); + } + alookup[256] = _mm_set_epi32(0, 0, 256 | (256 << 16), 256 | (256 << 16)); +} + +static void voodoo_codegen_close(voodoo_t *voodoo) +{ +#if WIN64 + VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); +#else + free(voodoo->codegen_data); +#endif +} + diff --git a/src/vid_voodoo_codegen_x86.h b/src/vid_voodoo_codegen_x86.h new file mode 100644 index 000000000..40d1503a7 --- /dev/null +++ b/src/vid_voodoo_codegen_x86.h @@ -0,0 +1,3725 @@ +/*Registers : + + alphaMode + fbzMode & 0x1f3fff + fbzColorPath +*/ + +#ifdef __linux__ +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#define BITMAP windows_BITMAP +#include +#undef BITMAP +#endif + +#include + +#define BLOCK_NUM 8 +#define BLOCK_MASK (BLOCK_NUM-1) +#define BLOCK_SIZE 8192 + +typedef struct voodoo_x86_data_t +{ + uint8_t code_block[BLOCK_SIZE]; + int xdir; + uint32_t alphaMode; + uint32_t fbzMode; + uint32_t fogMode; + uint32_t fbzColorPath; + uint32_t textureMode; + uint32_t trexInit1; +} voodoo_x86_data_t; + +static int last_block[2] = {0, 0}; +static int next_block_to_write[2] = {0, 0}; + +#define addbyte(val) \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addword(val) \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addlong(val) \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addquad(val) \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + + +static __m128i xmm_01_w;// = 0x0001000100010001ull; +static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; +static __m128i xmm_ff_b;// = 0x00000000ffffffffull; + +static uint32_t zero = 0; +static double const_1_48 = (double)(1ull << 4); + +static __m128i alookup[257], aminuslookup[256]; +static __m128i minus_254;// = 0xff02ff02ff02ff02ull; +static __m128i bilinear_lookup[256*4]; + +static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) +{ + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; +// xmm_01_w = (__m128i)0x0001000100010001ull; +// xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; +// xmm_ff_b = (__m128i)0x00000000ffffffffull; + xmm_01_w = _mm_set_epi32(0, 0, 0x00010001, 0x00010001); + xmm_ff_w = _mm_set_epi32(0, 0, 0x00ff00ff, 0x00ff00ff); + xmm_ff_b = _mm_set_epi32(0, 0, 0, 0x00ffffff); + minus_254 = _mm_set_epi32(0, 0, 0xff02ff02, 0xff02ff02); +// *(uint64_t *)&const_1_48 = 0x45b0000000000000ull; +// block_pos = 0; +// voodoo_get_depth = &code_block[block_pos]; + /*W at (%esp+4) + Z at (%esp+12) + new_depth at (%esp+16)*/ +// if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depth_op == DEPTHOP_NEVER)) +// { +// addbyte(0xC3); /*RET*/ +// return; +// } + addbyte(0x55); /*PUSH EBP*/ + addbyte(0x57); /*PUSH EDI*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0x53); /*PUSH EBX*/ + + addbyte(0x8b); /*MOV EDI, [ESP+4]*/ + addbyte(0x7c); + addbyte(0x24); + addbyte(4+16); + loop_jump_pos = block_pos; + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); + addbyte(0x66); /*PXOR XMM2, XMM2*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xd2); + + if ((params->fbzMode & FBZ_W_BUFFER) || (params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0xb8); /*MOV new_depth, 0*/ + addlong(0); + addbyte(0x66); /*TEST w+4, 0xffff*/ + addbyte(0xf7); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addword(0xffff); + addbyte(0x75); /*JNZ got_depth*/ + depth_jump_pos = block_pos; + addbyte(0); +// addbyte(4+5+2+3+2+5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0x8b); /*MOV EDX, w*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xb8); /*MOV new_depth, 0xf001*/ + addlong(0xf001); + addbyte(0x89); /*MOV EBX, EDX*/ + addbyte(0xd3); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x74); /*JZ got_depth*/ + depth_jump_pos2 = block_pos; + addbyte(0); +// addbyte(5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0xb9); /*MOV ECX, 19*/ + addlong(19); + addbyte(0x0f); /*BSR EAX, EDX*/ + addbyte(0xbd); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 15*/ + addlong(15); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + addbyte(0x29); /*SUB EDX, EAX - EDX = exp*/ + addbyte(0xc2); + addbyte(0x29); /*SUB ECX, EDX*/ + addbyte(0xd1); + addbyte(0xc1); /*SHL EDX, 12*/ + addbyte(0xe2); + addbyte(12); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + addbyte(0x81); /*AND EBX, 0xfff - EBX = mant*/ + addbyte(0xe3); + addlong(0xfff); + addbyte(0x8d); /*LEA EAX, 1[EDX, EBX]*/ + addbyte(0x44); + addbyte(0x13); + addbyte(1); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w_depth)); + } + } + if (!(params->fbzMode & FBZ_W_BUFFER)) + { + addbyte(0x8b); /*MOV EAX, z*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + if (params->fbzMode & FBZ_DEPTH_BIAS) + { + addbyte(0x03); /*ADD EAX, params->zaColor[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + addbyte(0x25); /*AND EAX, 0xffff*/ + addlong(0xffff); + } + + addbyte(0x89); /*MOV state->new_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + + if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop != DEPTHOP_ALWAYS) && (depthop != DEPTHOP_NEVER)) + { + addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x8b);/*MOV ECX, aux_mem[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x0f); /*MOVZX EBX, [ECX+EBX*2]*/ + addbyte(0xb7); + addbyte(0x1c); + addbyte(0x59); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + if (depthop == DEPTHOP_LESSTHAN) + { + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_EQUAL) + { + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_LESSTHANEQUAL) + { + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHAN) + { + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_NOTEQUAL) + { + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHANEQUAL) + { + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + z_skip_pos = block_pos; + addlong(0); + } + else + fatal("Bad depth_op\n"); + } + else if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop == DEPTHOP_NEVER)) + { + addbyte(0xC3); /*RET*/ +// addbyte(0x30); /*XOR EAX, EAX*/ +// addbyte(0xc0); + } +// else +// { +// addbyte(0xb0); /*MOV AL, 1*/ +// addbyte(1); +// } + + +// voodoo_combine = &code_block[block_pos]; + /*XMM0 = colour*/ + /*XMM2 = 0 (for unpacking*/ + + /*EDI = state, ESI = params*/ + + if (params->textureMode & 1) + { + /*CVTSI2SSq XMM6, state->w*/ + /*MOVSS XMM7, const_1_48*/ + /*DIVSS XMM7, XMM6*/ + /*CVTSI2SSq XMM4, state->tmu0_s*/ + /*MULSS XMM7, const_1_44*/ + /*CVTSI2SSq XMM5, state->tmu0_t*/ + /*MULSS XMM4, XMM7*/ + /*CVTSS2SIq state->tex_s, XMM4*/ + /*MULSS XMM5, XMM7*/ + /*CVTSS2SIq state->tex_t, XMM5*/ + + addbyte(0xdf); /*FILDq state->tmu0_w*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xdd); /*FLDq const_1_48*/ + addbyte(0x05); + addlong(&const_1_48); + addbyte(0xde); /*FDIV ST(1)*/ + addbyte(0xf1); + addbyte(0xdf); /*FILDq state->tmu0_s*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xdf); /*FILDq state->tmu0_t*/ /*ST(0)=t, ST(1)=s, ST(2)=1/w*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tmu0_t)); + addbyte(0xd9); /*FXCH ST(1)*/ /*ST(0)=s, ST(1)=t, ST(2)=1/w*/ + addbyte(0xc9); + addbyte(0xd8); /*FMUL ST(2)*/ /*ST(0)=s/w, ST(1)=t, ST(2)=1/w*/ + addbyte(0xca); + addbyte(0xd9); /*FXCH ST(1)*/ /*ST(0)=t, ST(1)=s/w, ST(2)=1/w*/ + addbyte(0xc9); + addbyte(0xd8); /*FMUL ST(2)*/ /*ST(0)=t/w, ST(1)=s/w, ST(2)=1/w*/ + addbyte(0xca); + addbyte(0xd9); /*FXCH ST(2)*/ /*ST(0)=1/w, ST(1)=s/w, ST(2)=t/w*/ + addbyte(0xca); + addbyte(0xd9); /*FSTPs log_temp*/ /*ST(0)=s/w, ST(1)=t/w*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, log_temp)); + addbyte(0xdf); /*FSITPq state->tex_s*/ + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EAX, log_temp*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, log_temp)); + addbyte(0xdf); /*FSITPq state->tex_t*/ + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0xc1); /*SHR EAX, 23-8*/ + addbyte(0xe8); + addbyte(15); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0x25); /*AND EAX, 0xff00*/ + addlong(0xff00); + addbyte(0x2d); /*SUB EAX, (127-44)<<8*/ + addlong((127-44+19) << 8); + addbyte(0x0f); /*MOVZX EBX, logtable[EBX]*/ + addbyte(0xb6); + addbyte(0x9b); + addlong(logtable); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); +// addbyte(0x89); /*MOV state->lod_raw, EAX*/ +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, lod_raw)); + addbyte(0x03); /*ADD EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu[0].lod)); +/*HACK*/ +#if 0 + addbyte(0x8b); /*MOV EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); +#endif + addbyte(0x3b); /*CMP EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x0f); /*CMOVL EAX, state->lod_min*/ + addbyte(0x4c); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x3b); /*CMP EAX, state->lod_max*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max)); + addbyte(0x0f); /*CMOVNL EAX, state->lod_max*/ + addbyte(0x4d); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max)); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + else + { + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_s*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM5, state->tmu0_t*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x66); /*SHRQ XMM4, 28*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd4); + addbyte(28); + addbyte(0x66); /*SHRQ XMM5, 28*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd5); + addbyte(28); + addbyte(0x66); /*MOVQ state->tex_s, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x66); /*MOVQ state->tex_t, XMM5*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x8b); /*MOV EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + + + if (voodoo->trexInit1 & (1 << 18)) + { +#if 0 + addbyte(0xc7); /*MOV state->tex_r, 0*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_r)); + addlong(0); + addbyte(0xc7); /*MOV state->tex_g, 0*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_g)); + addlong(0); + addbyte(0xc7); /*MOV state->tex_b, 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addlong(1); +#endif + addbyte(0xb8); /*MOV EAX, 0x000001*/ + addlong(0x000001); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + } + else if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (voodoo->bilinear_enabled && (params->textureMode & 6)) + { + addbyte(0x8b); /*MOV ECX, state->lod[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xbd); /*MOV EBP, 1*/ + addlong(1); + addbyte(0x8a); /*MOV DL, params->tex_shift[ESI+ECX*4]*/ + addbyte(0x94); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0xd3); /*SHL EBP, CL*/ + addbyte(0xe5); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHL EBP, 3*/ + addbyte(0xe5); + addbyte(3); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x29); /*SUB EAX, EBP*/ + addbyte(0xe8); + addbyte(0x29); /*SUB EBX, EBP*/ + addbyte(0xeb); + addbyte(0xd3); /*SAR EAX, CL*/ + addbyte(0xf8); + addbyte(0xd3); /*SAR EBX, CL*/ + addbyte(0xfb); + addbyte(0x89); /*MOV EBP, EAX*/ + addbyte(0xc5); + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + addbyte(0x83); /*AND EBP, 0xf*/ + addbyte(0xe5); + addbyte(0xf); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SAR EAX, 4*/ + addbyte(0xf8); + addbyte(4); + addbyte(0x81); /*AND ECX, 0xf0*/ + addbyte(0xe1); + addlong(0xf0); + addbyte(0xc1); /*SAR EBX, 4*/ + addbyte(0xfb); + addbyte(4); + addbyte(0x09); /*OR EBP, ECX*/ + addbyte(0xcd); + addbyte(0x8b); /*MOV ECX, state->lod[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xc1); /*SHL EBP, 6*/ + addbyte(0xe5); + addbyte(6); + /*EAX = S, EBX = T, ECX = LOD, EDX = tex_shift, ESI=params, EDI=state, EBP = bilinear shift*/ + addbyte(0x8d); /*LEA ESI, [ESI+ECX*4]*/ + addbyte(0x34); + addbyte(0x8e); + addbyte(0x89); /*MOV ebp_store, EBP*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x8b); /*MOV EBP, state->tex[EDI+ECX*4]*/ + addbyte(0xac); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex)); + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + if (!state->clamp_s) + { + addbyte(0x23); /*AND EAX, params->tex_w_mask[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + } + addbyte(0x83); /*ADD EDX, 1*/ + addbyte(0xc2); + addbyte(1); + if (state->clamp_t) + { + addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x48); + addbyte(0x15); + addlong(&zero); + addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x0f); /*CMOVA EDX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x85); /*TEST EBX,EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1d); + addlong(&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x0f); /*CMOVA EBX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + } + else + { + addbyte(0x23); /*AND EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x23); /*AND EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + } + /*EAX = S, EBX = T0, EDX = T1*/ + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0xd3); /*SHL EDX, CL*/ + addbyte(0xe2); + if (state->tformat & 8) + { + addbyte(0x8d); /*LEA EBX,[EBP+EBX*2]*/ + addbyte(0x5c); + addbyte(0x5d); + addbyte(0); + addbyte(0x8d); /*LEA EDX,[EBP+EDX*2]*/ + addbyte(0x54); + addbyte(0x55); + addbyte(0); + } + else + { + addbyte(0x01); /*ADD EBX, EBP*/ + addbyte(0xeb); + addbyte(0x01); /*ADD EDX, EBP*/ + addbyte(0xea); + } + if (state->clamp_s) + { + addbyte(0x8b); /*MOV EBP, params->tex_w_mask[ESI]*/ + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x8b); /*MOV ebp_store2, ESI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x05); + addlong(&zero); + addbyte(0x78); /*JS + - clamp on 0*/ + addbyte(2+3+2+ ((state->tformat & 8) ? (3+3+2) : (4+4+2))); + addbyte(0x3b); /*CMP EAX, EBP*/ + addbyte(0xc5); + addbyte(0x0f); /*CMOVAE EAX, EBP*/ + addbyte(0x43); + addbyte(0xc5); + addbyte(0x73); /*JAE + - clamp on +*/ + addbyte((state->tformat & 8) ? (3+3+2) : (4+4+2)); + } + else + { + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI] - is S at texture edge (ie will wrap/clamp)?*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + addbyte(0x8b); /*MOV ebp_store2, ESI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x74); /*JE +*/ + addbyte((state->tformat & 8) ? (3+3+2) : (4+4+2)); + } + + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV EDX,[EDX+EAX*2]*/ + addbyte(0x14); + addbyte(0x42); + addbyte(0x8b); /*MOV EAX,[EBX+EAX*2]*/ + addbyte(0x04); + addbyte(0x43); + } + else + { + addbyte(0x0f); /*MOVZX EDX,W[EDX+EAX]*/ + addbyte(0xb7); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,W[EBX+EAX]*/ + addbyte(0xb7); + addbyte(0x04); + addbyte(0x03); + } + + if (state->clamp_s) + { + addbyte(0xeb); /*JMP +*/ + addbyte((state->tformat & 8) ? (3+4+3+3+4+3) : (4+4+2+2)); + + /*S clamped - the two S coordinates are the same*/ + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV ECX, [EDX+EAX*2]*/ + addbyte(0x0c); + addbyte(0x42); + addbyte(0x8b); /*MOV EDX, [EDX+EAX*2-2]*/ + addbyte(0x54); + addbyte(0x42); + addbyte(-2); + addbyte(0x66); /*MOV DX, CX*/ + addbyte(0x89); + addbyte(0xca); + addbyte(0x8b); /*MOV ECX, [EBX+EAX*2]*/ + addbyte(0x0c); + addbyte(0x43); + addbyte(0x8b); /*MOV EAX, [EBX+EAX*2-2]*/ + addbyte(0x44); + addbyte(0x43); + addbyte(-2); + addbyte(0x66); /*MOV AX, CX*/ + addbyte(0x89); + addbyte(0xc8); + } + else + { + addbyte(0x0f); /*MOVZX EDX,W[EDX+EAX]*/ + addbyte(0xb7); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,W[EBX+EAX]*/ + addbyte(0xb7); + addbyte(0x04); + addbyte(0x03); + addbyte(0x88); /*MOV DH, DL*/ + addbyte(0xd6); + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + } + } + else + { + addbyte(0xeb); /*JMP +*/ + addbyte((state->tformat & 8) ? (3+3+3+3+3+3) : (2+2+4+4+2+2)); + + /*S wrapped - the two S coordinates are not contiguous*/ + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV ECX, [EDX+EAX*2]*/ + addbyte(0x0c); + addbyte(0x42); + addbyte(0x8b); /*MOV EDX, [EDX-2]*/ + addbyte(0x52); + addbyte(-2); + addbyte(0x66); /*MOV DX, CX*/ + addbyte(0x89); + addbyte(0xca); + addbyte(0x8b); /*MOV ECX, [EBX+EAX*2]*/ + addbyte(0x0c); + addbyte(0x43); + addbyte(0x8b); /*MOV EAX, [EBX-2]*/ + addbyte(0x43); + addbyte(-2); + addbyte(0x66); /*MOV AX, CX*/ + addbyte(0x89); + addbyte(0xc8); + } + else + { + addbyte(0x8a); /*MOV CL, [EDX]*/ + addbyte(0x0a); + addbyte(0x8a); /*MOV CH, [EBX]*/ + addbyte(0x2b); + addbyte(0x0f); /*MOVZX EDX,B[EDX+EAX]*/ + addbyte(0xb6); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,B[EBX+EAX]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x03); + addbyte(0x88); /*MOV DH, CL*/ + addbyte(0xce); + addbyte(0x88); /*MOV AH, CH*/ + addbyte(0xec); + } + } + + addbyte(0x81); /*ADD ESI, bilinear_lookup*/ + addbyte(0xc6); + addlong(bilinear_lookup); + + switch (state->tformat) + { + case TEX_RGB332: + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, rgb332[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(rgb332); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, rgb332[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x8d); + addlong(rgb332); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, rgb332[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(rgb332); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, rgb332[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x8d); + addlong(rgb332); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_Y4I2Q2: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_A8: + addbyte(0x66); /*MOVZX CX, AH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*MOVZX AX, AL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xc0); + addbyte(0x66); /*IMUL CX, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*IMUL AX, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x06); + addbyte(0x66); /*MOVZX BX, DH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xde); + addbyte(0x66); /*MOVZX DX, DL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xd2); + addbyte(0x66); /*ADD AX, CX*/ + addbyte(0x01); + addbyte(0xc8); + addbyte(0x66); /*IMUL BX, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x5e); + addbyte(0x30); + addbyte(0x66); /*IMUL DX, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x56); + addbyte(0x20); + addbyte(0x66); /*ADD AX, BX*/ + addbyte(0x01); + addbyte(0xd8); + addbyte(0x66); /*ADD AX, DX*/ + addbyte(0x01); + addbyte(0xd0); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x66); /*MOV BX, AX*/ + addbyte(0x89); + addbyte(0xc3); + addbyte(0x0f); /*BSWAP EAX*/ + addbyte(0xc8); + addbyte(0x66); /*MOV AX, BX*/ + addbyte(0x89); + addbyte(0xd8); + break; + + case TEX_I8: + addbyte(0x66); /*MOVZX CX, AH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*MOVZX AX, AL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xc0); + addbyte(0x66); /*IMUL CX, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*IMUL AX, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x06); + addbyte(0x66); /*MOVZX BX, DH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xde); + addbyte(0x66); /*MOVZX DX, DL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xd2); + addbyte(0x66); /*ADD AX, CX*/ + addbyte(0x01); + addbyte(0xc8); + addbyte(0x66); /*IMUL BX, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x5e); + addbyte(0x30); + addbyte(0x66); /*IMUL DX, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x56); + addbyte(0x20); + addbyte(0x66); /*ADD AX, BX*/ + addbyte(0x01); + addbyte(0xd8); + addbyte(0x66); /*ADD AX, DX*/ + addbyte(0x01); + addbyte(0xd0); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_AI8: + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, ai44[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(ai44); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, ai44[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x8d); + addlong(ai44); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, ai44[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(ai44); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, ai44[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x8d); + addlong(ai44); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_PAL8: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_R5G6B5: + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, rgb565[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(rgb565); + addbyte(0x66); /*MOVD XMM1, rgb565[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x85); + addlong(rgb565); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, rgb565[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(rgb565); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, rgb565[EDX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x95); + addlong(rgb565); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_ARGB1555: + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, argb1555[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(argb1555); + addbyte(0x66); /*MOVD XMM1, argb1555[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x85); + addlong(argb1555); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, argb1555[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(argb1555); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, argb1555[EDX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x95); + addlong(argb1555); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_ARGB4444: + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, argb4444[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(argb4444); + addbyte(0x66); /*MOVD XMM1, argb4444[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x85); + addlong(argb4444); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, argb4444[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(argb4444); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, argb4444[EDX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x95); + addlong(argb4444); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_A8I8: + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, ai88[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(ai88); + addbyte(0x66); /*MOVD XMM1, ai88[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x85); + addlong(ai88); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, ai88[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(ai88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, ai88[EDX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x95); + addlong(ai88); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_APAL88: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*PINSRW XMM0, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc1); + addbyte(3); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PINSRW XMM1, EAX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc8); + addbyte(3); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PINSRW XMM3, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xd9); + addbyte(3); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PINSR1 XMM1, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc9); + addbyte(3); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } + + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); /*CHECK!*/ + } + else + { + addbyte(0x8b); /*MOV ECX, state->lod[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0x8a); /*MOV DL, params->tex_shift[ESI+ECX*4]*/ + addbyte(0x94); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0x8b); /*MOV EBP, state->tex[EDI+ECX*4]*/ + addbyte(0xac); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex)); + addbyte(0x80); /*ADD CL, 4*/ + addbyte(0xc1); + addbyte(4); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0xd3); /*SHR EAX, CL*/ + addbyte(0xe8); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + if (state->clamp_s) + { + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x05); + addlong(&zero); + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + addbyte(0x0f); /*CMOVAE EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + + } + else + { + addbyte(0x23); /*AND EAX, params->tex_w_mask-0x10[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + } + if (state->clamp_t) + { + addbyte(0x85); /*TEST EBX, EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1d); + addlong(&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + addbyte(0x0f); /*CMOVAE EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + } + else + { + addbyte(0x23); /*AND EBX, params->tex_h_mask-0x10[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + } + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0x01); /*ADD EBX, EAX*/ + addbyte(0xc3); + + if (state->tformat & 8) + { + addbyte(0x0f); /*MOVZX EAX,W[EBP+EBX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x5d); + addbyte(0); + } + else + { + addbyte(0x0f); /*MOVZX EAX,B[EBP+EBX]*/ + addbyte(0xb6); + addbyte(0x44); + addbyte(0x1d); + addbyte(0); + } + + switch (state->tformat) + { + case TEX_RGB332: + addbyte(0x8b); /*MOV EAX, rgb332[EAX*4]*/ + addbyte(0x04); + addbyte(0x85); + addlong(rgb332); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_Y4I2Q2: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); +// addbyte(0x0f); /*BSWAP EAX*/ +// addbyte(0xc8); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_A8: + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0x66); /*MOV BX, AX*/ + addbyte(0x89); + addbyte(0xc3); + addbyte(0x0f); /*BSWAP EAX*/ + addbyte(0xc8); + addbyte(0x66); /*MOV AX, BX*/ + addbyte(0x89); + addbyte(0xd8); + break; + + case TEX_I8: + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); +// addbyte(0x25); /*AND EAX, 0x00ffffff*/ +// addlong(0x00000000); + break; + + case TEX_AI8: + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*AND EAX, 0x0f*/ + addbyte(0xe0); + addbyte(0x0f); + addbyte(0x81); /*AND EBX, 0xf0*/ + addbyte(0xe3); + addlong(0xf0); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SHR EDX, 4*/ + addbyte(0xe2); + addbyte(4); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + addbyte(0x09); /*OR EBX, EDX*/ + addbyte(0xd3); + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0xc1); /*SHL EBX, 24*/ + addbyte(0xe3); + addbyte(24); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + break; + + case TEX_PAL8: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); +// addbyte(0x0f); /*BSWAP EAX*/ +// addbyte(0xc8); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_R5G6B5: + addbyte(0x8b); /*MOV EAX, rgb565[EAX*4]*/ + addbyte(0x04); + addbyte(0x85); + addlong(rgb565); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_ARGB1555: + addbyte(0x8b); /*MOV EAX, argb1555[EAX*4]*/ + addbyte(0x04); + addbyte(0x85); + addlong(argb1555); + break; + + case TEX_ARGB4444: + addbyte(0x8b); /*MOV EAX, argb4444[EAX*4]*/ + addbyte(0x04); + addbyte(0x85); + addlong(argb4444); + break; + + case TEX_A8I8: + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0xc1); /*SHL EAX, 16*/ + addbyte(0xe0); + addbyte(16); + addbyte(0x88); /*MOV AL, BL*/ + addbyte(0xd8); + addbyte(0x88); /*MOV AH, BL*/ + addbyte(0xdc); + break; + + case TEX_APAL88: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x25); /*AND EAX, 0x000000ff*/ + addlong(0x000000ff); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); + addbyte(0xc1); /*SHL EBX, 16*/ + addbyte(0xe3); + addbyte(16); +// addbyte(0x0f); /*BSWAP EAX*/ +// addbyte(0xc8); + addbyte(0x81); /*AND EBX, 0xff000000*/ + addbyte(0xe3); + addlong(0xff000000); + addbyte(0x25); /*AND EAX, 0x00ffffff*/ + addlong(0x00ffffff); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + +// addbyte(0x25); /*AND EAX, 0x00ffffff*/ +// addlong(0x00000000); + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } + } + if ((params->fbzMode & FBZ_CHROMAKEY)) + { + addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, chromaKey)); + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x81); /*AND EBX, 0xffffff*/ + addbyte(0xe3); + addlong(0xffffff); + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + chroma_skip_pos = block_pos; + addlong(0); + } +#if 0 + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0x89); /*MOV state->tex_b[EDI], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x0f); /*MOVZX EBX, AH*/ + addbyte(0xb6); + addbyte(0xdc); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x89); /*MOV state->tex_g[EDI], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_g)); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0x89); /*MOV state->tex_r[EDI], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_r)); + addbyte(0x0f); /*MOVZX EBX, AH*/ + addbyte(0xb6); + addbyte(0xdc); + addbyte(0x89); /*MOV state->tex_a[EDI], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); +#endif +//#if 0 +// addbyte(0x89); /*MOV state->tex_out[EDI], EAX*/ +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, tex_out)); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); +//#endif + } + + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + /*EBX = a_other*/ + switch (a_sel) + { + case A_SEL_ITER_A: + addbyte(0x8b); /*MOV EBX, state->ia*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1); /*SAR EBX, 12*/ + addbyte(0xfb); + addbyte(12); + addbyte(0x0f); /*CMOVS EBX, EAX*/ + addbyte(0x48); + addbyte(0xd8); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVA EBX, EDX*/ + addbyte(0x47); + addbyte(0xda); + break; + case A_SEL_TEX: + addbyte(0x8b); /*MOV EBX, state->tex_a*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + case A_SEL_COLOR1: + addbyte(0x0f); /*MOVZX EBX, params->color1+3*/ + addbyte(0xb6); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, color1)+3); + break; + default: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + } + /*ECX = a_local*/ + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + if (a_sel == A_SEL_ITER_A) + { + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + } + else + { + addbyte(0x8b); /*MOV ECX, state->ia*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1);/*SAR ECX, 12*/ + addbyte(0xf9); + addbyte(12); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + } + break; + case CCA_LOCALSELECT_COLOR0: + addbyte(0x0f); /*MOVZX ECX, params->color0+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)+3); + break; + case CCA_LOCALSELECT_ITER_Z: + addbyte(0x8b); /*MOV ECX, state->z*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, z)); + if (a_sel != A_SEL_ITER_A) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + } + addbyte(0xc1);/*SAR ECX, 20*/ + addbyte(0xf9); + addbyte(20); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + break; + + default: + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + break; + } + + if (cca_zero_other) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + } + + if (cca_sub_clocal) + { + addbyte(0x29); /*SUB EDX, ECX*/ + addbyte(0xca); + } + } + + if (cc_sub_clocal || cc_mselect == 1 || cc_add == 1) + { + /*XMM1 = local*/ + if (!cc_localselect_override) + { + if (cc_localselect) + { + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + } + else + { + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + } + else + { + addbyte(0xf6); /*TEST state->tex_a, 0x80*/ + addbyte(0x87); + addbyte(0x23); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0x80); + addbyte(0x74);/*JZ !cc_localselect*/ + addbyte(8+2); + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + /*JMP +*/ + /*!cc_localselect:*/ + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + } + if (!cc_zero_other) + { + if (_rgb_sel == CC_LOCALSELECT_ITER_RGB) + { + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + else if (_rgb_sel == CC_LOCALSELECT_TEX) + { +#if 0 + addbyte(0xf3); /*MOVDQU XMM0, state->tex_b*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); +#endif + } + else if (_rgb_sel == CC_LOCALSELECT_COLOR1) + { + addbyte(0x66); /*MOVD XMM0, params->color1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + } + else + { + /*MOVD XMM0, src_r*/ + } + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + else + { + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + if (!(cca_mselect == 0 && cca_reverse_blend == 0)) + { + switch (cca_mselect) + { + case CCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_AOTHER: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case CCA_MSELECT_ALOCAL2: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_TEX: + addbyte(0x0f); /*MOVZX EAX, state->tex_a*/ + addbyte(0xb6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + + case CCA_MSELECT_ZERO: + default: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + } + if (!cca_reverse_blend) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EDX, EAX*/ + addbyte(0xaf); + addbyte(0xd0); + addbyte(0xc1); /*SHR EDX, 8*/ + addbyte(0xea); + addbyte(8); + } + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) + { + /*Copy a_other to XMM3 before it gets modified*/ + addbyte(0x66); /*MOVD XMM3, EDX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xda); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + } + + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x01); /*ADD EDX, ECX*/ + addbyte(0xca); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x85); /*TEST EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*CMOVS EDX, EAX*/ + addbyte(0x48); + addbyte(0xd0); + addbyte(0xb8); /*MOV EAX, 0xff*/ + addlong(0xff); + addbyte(0x81); /*CMP EDX, 0xff*/ + addbyte(0xfa); + addlong(0xff); + addbyte(0x0f); /*CMOVA EDX, EAX*/ + addbyte(0x47); + addbyte(0xd0); + + if (cca_invert_output) + { + addbyte(0x81); /*XOR EDX, 0xff*/ + addbyte(0xf2); + addlong(0xff); + } + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0)) + { + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + case CC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + break; + case CC_MSELECT_ALOCAL: + addbyte(0x66); /*MOVD XMM3, ECX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd9); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + break; + case CC_MSELECT_AOTHER: + /*Handled above*/ + break; + case CC_MSELECT_TEX: + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 1*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(1); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(2); + break; + default: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + } + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + if (!cc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x1d); + addlong(&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x1d); + addlong(&xmm_01_w); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM4, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xe3); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc4); + addbyte(0x66); /*PSRLD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + } + + if (cc_add == 1) + { + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + if (cc_invert_output) + { + addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x05); + addlong(&xmm_ff_b); + } +//#if 0 +// addbyte(0x66); /*MOVD state->out[EDI], XMM0*/ +// addbyte(0x0f); +// addbyte(0x7e); +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, out)); + if (params->fogMode & FOG_ENABLE) + { + if (params->fogMode & FOG_CONSTANT) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PADDUSB XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xdc); + addbyte(0xc3); +/* src_r += params->fogColor.r; + src_g += params->fogColor.g; + src_b += params->fogColor.b; */ + } + else + { + /*int fog_r, fog_g, fog_b, fog_a; */ + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + + if (!(params->fogMode & FOG_ADD)) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + else + { + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + } + + if (!(params->fogMode & FOG_MULT)) + { + addbyte(0x66); /*PSUBW XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xd8); + } + + /*Divide by 2 to prevent overflow on multiply*/ + addbyte(0x66); /*PSRAW XMM3, 1*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(1); + + if (params->fogMode & FOG_Z) + { + addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); +// fog_a = (z >> 20) & 0xff; + } + else if (params->fogMode & FOG_ALPHA) + { + addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(ia >> 12); + } + else + { + addbyte(0x8b); /*MOV EBX, state->w_depth[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, w_depth)); + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + addbyte(0xc1); /*SHR EBX, 10*/ + addbyte(0xeb); + addbyte(10); + addbyte(0xc1); /*SHR EAX, 2*/ + addbyte(0xe8); + addbyte(2); + addbyte(0x83); /*AND EBX, 0x3f*/ + addbyte(0xe3); + addbyte(0x3f); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0xf6); /*MUL params->fogTable+1[ESI+EBX*2]*/ + addbyte(0xa4); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)+1); + addbyte(0x0f); /*MOVZX EBX, params->fogTable[ESI+EBX*2]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)); + addbyte(0xc1); /*SHR EAX, 10*/ + addbyte(0xe8); + addbyte(10); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + +/* int fog_idx = (w_depth >> 10) & 0x3f; + + fog_a = params->fogTable[fog_idx].fog; + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10;*/ + } + addbyte(0x01); /*ADD EAX, EAX*/ + addbyte(0xc0); +// fog_a++; + + addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x1c); + addbyte(0xc5); + addlong(((uintptr_t)alookup) + 16); + addbyte(0x66); /*PSRAW XMM3, 7*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(7); +/* fog_r = (fog_r * fog_a) >> 8; + fog_g = (fog_g * fog_a) >> 8; + fog_b = (fog_b * fog_a) >> 8;*/ + + if (params->fogMode & FOG_MULT) + { + addbyte(0xf3); /*MOV XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); +/* src_r += fog_r; + src_g += fog_g; + src_b += fog_b;*/ + } + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + +/* src_r = CLAMP(src_r); + src_g = CLAMP(src_g); + src_b = CLAMP(src_b);*/ + } + + if ((params->alphaMode & 1) && (alpha_func != AFUNC_NEVER) && (alpha_func != AFUNC_ALWAYS)) + { + addbyte(0x0f); /*MOVZX ECX, params->alphaMode+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, alphaMode) + 3); + addbyte(0x39); /*CMP EDX, ECX*/ + addbyte(0xca); + + switch (alpha_func) + { + case AFUNC_LESSTHAN: + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_EQUAL: + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_LESSTHANEQUAL: + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHAN: + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_NOTEQUAL: + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHANEQUAL: + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + a_skip_pos = block_pos; + addlong(0); + break; + } + } + else if ((params->alphaMode & 1) && (alpha_func == AFUNC_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + if (params->alphaMode & (1 << 4)) + { + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x8b); /*MOV EBP, fb_mem*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x01); /*ADD EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*MOVZX EAX, [EBP+EAX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x45); + addbyte(0); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, rgb565[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x24); + addbyte(0x85); + addlong(rgb565); + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOV XMM6, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xf4); + + switch (dest_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe0); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2d); + addlong(&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe5); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASATURATE: + addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x25); + addlong(&minus_254); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + } + + switch (src_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong(alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM0, XMM6*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc6); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong(aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2d); + addlong(&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM6*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xee); + addbyte(0x66); /*PMULLW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc5); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ACOLORBEFOREFOG: + break; + } + + addbyte(0x66); /*PADDW XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc4); + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } +//#endif + +// addbyte(0x8b); /*MOV EDX, x (ESP+12)*/ +// addbyte(0x54); +// addbyte(0x24); +// addbyte(12); + + + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + + if (params->fbzMode & FBZ_RGB_WMASK) + { +// addbyte(0x89); /*MOV state->rgb_out[EDI], EAX*/ +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, rgb_out)); + + if (dither) + { + addbyte(0x8b); /*MOV ESI, real_y (ESP+16)*/ + addbyte(0x74); + addbyte(0x24); + addbyte(16+16); + addbyte(0x0f); /*MOVZX EBX, AH*/ /*G*/ + addbyte(0xb6); + addbyte(0xdc); + if (dither2x2) + { + addbyte(0x83); /*AND EDX, 1*/ + addbyte(0xe2); + addbyte(1); + addbyte(0x83); /*AND ESI, 1*/ + addbyte(0xe6); + addbyte(1); + addbyte(0xc1); /*SHL EBX, 2*/ + addbyte(0xe3); + addbyte(2); + } + else + { + addbyte(0x83); /*AND EDX, 3*/ + addbyte(0xe2); + addbyte(3); + addbyte(0x83); /*AND ESI, 3*/ + addbyte(0xe6); + addbyte(3); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + } + addbyte(0x0f); /*MOVZX ECX, AL*/ /*R*/ + addbyte(0xb6); + addbyte(0xc8); + if (dither2x2) + { + addbyte(0xc1); /*SHR EAX, 14*/ + addbyte(0xe8); + addbyte(14); + addbyte(0x8d); /*LEA ESI, EDX+ESI*2*/ + addbyte(0x34); + addbyte(0x72); + } + else + { + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x8d); /*LEA ESI, EDX+ESI*4*/ + addbyte(0x34); + addbyte(0xb2); + } + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + if (dither2x2) + { + addbyte(0xc1); /*SHL ECX, 2*/ + addbyte(0xe1); + addbyte(2); + addbyte(0x25); /*AND EAX, 0x3fc*/ /*B*/ + addlong(0x3fc); + } + else + { + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0x25); /*AND EAX, 0xff0*/ /*B*/ + addlong(0xff0); + } + addbyte(0x0f); /*MOVZX EBX, dither_g[EBX+ESI]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x33); + addlong(dither2x2 ? dither_g2x2 : dither_g); + addbyte(0x0f); /*MOVZX ECX, dither_rb[ECX+ESI]*/ + addbyte(0xb6); + addbyte(0x8c); + addbyte(0x31); + addlong(dither2x2 ? dither_rb2x2 : dither_rb); + addbyte(0x0f); /*MOVZX EAX, dither_rb[EAX+ESI]*/ + addbyte(0xb6); + addbyte(0x84); + addbyte(0x30); + addlong(dither2x2 ? dither_rb2x2 : dither_rb); + addbyte(0xc1); /*SHL EBX, 5*/ + addbyte(0xe3); + addbyte(5); + addbyte(0xc1); /*SHL EAX, 11*/ + addbyte(0xe0); + addbyte(11); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + else + { + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0xc1); /*SHR EAX, 3*/ + addbyte(0xe8); + addbyte(3); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0xc1); /*SHL ECX, 3*/ + addbyte(0xe1); + addbyte(3); + addbyte(0x81); /*AND EAX, 0x001f*/ + addbyte(0xe0); + addlong(0x001f); + addbyte(0x81); /*AND EBX, 0xf800*/ + addbyte(0xe3); + addlong(0xf800); + addbyte(0x81); /*AND ECX, 0x07e0*/ + addbyte(0xe1); + addlong(0x07e0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + addbyte(0x8b); /*MOV ESI, fb_mem*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (params->fbzMode & FBZ_DEPTH_WMASK) + { + addbyte(0x66); /*MOV AX, new_depth*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + addbyte(0x8b); /*MOV ESI, aux_mem*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (z_skip_pos) + *(uint32_t *)&code_block[z_skip_pos] = (block_pos - z_skip_pos) - 4; + if (a_skip_pos) + *(uint32_t *)&code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; + if (chroma_skip_pos) + *(uint32_t *)&code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; + + + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); + + addbyte(0xf3); /*MOVDQU XMM1, state->ib[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVDQU XMM3, state->tmu0_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xf3); /*MOVDQU XMM0, params->dBdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dBdX)); + addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dZdX)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[0].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[0].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[0].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[0].dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfe); + addbyte(0xc8); + } + else + { + addbyte(0x66); /*PSUBD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfa); + addbyte(0xc8); + } + + addbyte(0xf3); /*MOVQ XMM0, state->w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xf3); /*MOVDQU state->ib, XMM1*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVQ XMM7, params->dWdX*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xbe); + addlong(offsetof(voodoo_params_t, dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + addbyte(0x66); /*PADDQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xc7); + addbyte(0x01); /*ADD state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + addbyte(0x66); /*PSUBQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xc7); + addbyte(0x29); /*SUB state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + + addbyte(0xf3); /*MOVDQU state->tmu0_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x66); /*MOVQ state->tmu0_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x66); /*MOVQ state->w, XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, pixel_count)); + addbyte(1); + + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + if (state->xdir > 0) + { + addbyte(0x83); /*ADD state->x[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + else + { + addbyte(0x83); /*SUB state->x[EDI], 1*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + + addbyte(0x3b); /*CMP EAX, state->x2[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x2)); + addbyte(0x0f); /*JNZ loop_jump_pos*/ + addbyte(0x85); + addlong(loop_jump_pos - (block_pos + 4)); + + addbyte(0x5b); /*POP EBX*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5d); /*POP EBP*/ + + addbyte(0xC3); /*RET*/ +} +static int voodoo_recomp = 0; +static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) +{ + int c; + int b = last_block[odd_even]; + voodoo_x86_data_t *data; + voodoo_x86_data_t *codegen_data = voodoo->codegen_data; + + for (c = 0; c < 8; c++) + { + data = &codegen_data[odd_even + b*2]; + + if (state->xdir == data->xdir && + params->alphaMode == data->alphaMode && + params->fbzMode == data->fbzMode && + params->fogMode == data->fogMode && + params->fbzColorPath == data->fbzColorPath && + (voodoo->trexInit1 & (1 << 18)) == data->trexInit1 && + params->textureMode == data->textureMode) + { + last_block[odd_even] = b; + return data->code_block; + } + + b = (b + 1) & 7; + } +voodoo_recomp++; + data = &codegen_data[odd_even + next_block_to_write[odd_even]*2]; +// code_block = data->code_block; + + voodoo_generate(data->code_block, voodoo, params, state, depth_op); + + data->xdir = state->xdir; + data->alphaMode = params->alphaMode; + data->fbzMode = params->fbzMode; + data->fogMode = params->fogMode; + data->fbzColorPath = params->fbzColorPath; + data->trexInit1 = voodoo->trexInit1 & (1 << 18); + data->textureMode = params->textureMode; + + next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; + + return data->code_block; +} + +static void voodoo_codegen_init(voodoo_t *voodoo) +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if defined WIN32 || defined _WIN32 || defined _WIN32 + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM*2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM*2); +#endif + +#ifdef __linux__ + start = (void *)((long)voodoo->codegen_data & pagemask); + len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif + + for (c = 0; c < 256; c++) + { + int d[4]; + int _ds = c & 0xf; + int dt = c >> 4; + + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); + aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); + + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + + bilinear_lookup[c*4] = _mm_set_epi32(0, 0, d[0] | (d[0] << 16), d[0] | (d[0] << 16)); + bilinear_lookup[c*4 + 1] = _mm_set_epi32(0, 0, d[1] | (d[1] << 16), d[1] | (d[1] << 16)); + bilinear_lookup[c*4 + 2] = _mm_set_epi32(0, 0, d[2] | (d[2] << 16), d[2] | (d[2] << 16)); + bilinear_lookup[c*4 + 3] = _mm_set_epi32(0, 0, d[3] | (d[3] << 16), d[3] | (d[3] << 16)); + } + alookup[256] = _mm_set_epi32(0, 0, 256 | (256 << 16), 256 | (256 << 16)); +} + +static void voodoo_codegen_close(voodoo_t *voodoo) +{ +#if defined WIN32 || defined _WIN32 || defined _WIN32 + VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); +#else + free(voodoo->codegen_data); +#endif +} diff --git a/src/vid_voodoo_dither.h b/src/vid_voodoo_dither.h new file mode 100644 index 000000000..21baf772b --- /dev/null +++ b/src/vid_voodoo_dither.h @@ -0,0 +1,5136 @@ +uint8_t dither_rb[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {1, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 0, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 1}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 1, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {0, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {2, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 1, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 2}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 2, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {1, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {1, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {3, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 3, 2}, + {2, 2, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 2, 2, 2}, + {3, 2, 3, 2}, + {2, 3, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 2, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 3, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 3}, + {2, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {2, 3, 2, 3}, + {3, 3, 3, 3}, + {3, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {2, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {4, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 4, 3}, + {3, 3, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 3, 3, 3}, + {4, 3, 4, 3}, + {3, 4, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 3, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 4, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 4}, + {3, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 3, 4}, + {4, 4, 4, 4}, + {4, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {5, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 4, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 5}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 5, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {4, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {6, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 5, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 6}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 6, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 5, 6}, + {6, 6, 6, 6}, + {6, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {7, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 7, 6}, + {6, 6, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 6}, + {7, 6, 7, 6}, + {6, 7, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 6, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 7, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 7}, + {6, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 6, 7}, + {7, 7, 7, 7}, + {7, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {8, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 8, 7}, + {7, 7, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 7}, + {8, 7, 8, 7}, + {7, 8, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 7, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 8, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 7, 8}, + {8, 8, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {9, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 8, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 9}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 9, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {8, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {10, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 9, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 10}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {9, 10, 9, 10}, + {10, 10, 10, 10}, + {10, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {9, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {11, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 11, 10}, + {10, 10, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 10, 10, 10}, + {11, 10, 11, 10}, + {10, 11, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 10, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 11}, + {11, 10, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 11}, + {11, 11, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 11}, + {10, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {10, 11, 10, 11}, + {11, 11, 11, 11}, + {11, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {10, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {12, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 12, 11}, + {11, 11, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 11, 11, 11}, + {12, 11, 12, 11}, + {11, 12, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 11, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 12}, + {12, 11, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 12, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {11, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 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, 13, 12}, + {12, 12, 12, 12}, + {13, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {13, 12, 13, 12}, + {12, 12, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 12, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 13}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 13}, + {12, 13, 12, 13}, + {13, 13, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 13, 13, 13}, + {12, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {12, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 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, 14, 13}, + {13, 13, 13, 13}, + {14, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {14, 13, 14, 13}, + {13, 13, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 13, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 14, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 14}, + {13, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {13, 14, 13, 14}, + {14, 14, 14, 14}, + {14, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {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}, + {15, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 15, 14}, + {14, 14, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 14, 14, 14}, + {15, 14, 15, 14}, + {14, 15, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 14, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 14, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 15, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 15}, + {14, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {14, 15, 14, 15}, + {15, 15, 15, 15}, + {15, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {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}, + {16, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 16, 15}, + {15, 15, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 15, 15, 15}, + {16, 15, 16, 15}, + {15, 16, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 15, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 15, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 16, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 16}, + {15, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {15, 16, 15, 16}, + {16, 16, 16, 16}, + {16, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {15, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {17, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 17, 16}, + {16, 16, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 16, 16, 16}, + {17, 16, 17, 16}, + {16, 17, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 16, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 16, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 17, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 17}, + {16, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {16, 17, 16, 17}, + {17, 17, 17, 17}, + {17, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {16, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {18, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 18, 17}, + {17, 17, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 17, 17, 17}, + {18, 17, 18, 17}, + {17, 18, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 17, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 18}, + {17, 18, 17, 18}, + {18, 18, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 18, 18, 18}, + {17, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {17, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 19, 18}, + {18, 18, 18, 18}, + {19, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {19, 18, 19, 18}, + {18, 18, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 18, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 19}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 19}, + {18, 19, 18, 19}, + {19, 19, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 19, 19, 19}, + {18, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {18, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 20, 19}, + {19, 19, 19, 19}, + {20, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {20, 19, 20, 19}, + {19, 19, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 19, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 19, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 19, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 20, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 20}, + {19, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {19, 20, 19, 20}, + {20, 20, 20, 20}, + {20, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {19, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {21, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 21, 20}, + {20, 20, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 20, 20, 20}, + {21, 20, 21, 20}, + {20, 21, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 20, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 21, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 21}, + {20, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {20, 21, 20, 21}, + {21, 21, 21, 21}, + {21, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {20, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {22, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 22, 21}, + {21, 21, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 21, 21, 21}, + {22, 21, 22, 21}, + {21, 22, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 21, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 22}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 22, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {21, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {23, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 22, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 23}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 23, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {22, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 24, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 23, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 24, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 24}, + {23, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 23, 24}, + {24, 24, 24, 24}, + {24, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {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}, + {25, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 25, 24}, + {24, 24, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 24}, + {25, 24, 25, 24}, + {24, 25, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 24, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 25, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 25}, + {24, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 24, 25}, + {25, 25, 25, 25}, + {25, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {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}, + {26, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 25}, + {26, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 26}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 26, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {25, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 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, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {27, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 26, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 27}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 27, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {26, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 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, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 27}, + {28, 27, 28, 27}, + {27, 28, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 27, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 28, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 28}, + {27, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {27, 28, 27, 28}, + {28, 28, 28, 28}, + {28, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {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}, + {29, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 29, 28}, + {28, 28, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 28, 28, 28}, + {29, 28, 29, 28}, + {28, 29, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 28, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 29}, + {29, 28, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 29}, + {29, 29, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 29}, + {28, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {28, 29, 28, 29}, + {29, 29, 29, 29}, + {29, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {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}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {30, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 29, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 30}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 30, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {29, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {31, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 30, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 31}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 31, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {30, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {31, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 31, 31}, + }, +}; + +uint8_t dither_g[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {1, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 1}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 1, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {2, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 2}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 2, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {3, 2, 3, 2}, + {2, 2, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 3, 3, 3}, + {2, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {4, 3, 4, 3}, + {3, 3, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 4, 4, 4}, + {3, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 4, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 5}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {4, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 5, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 6}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 7, 6}, + {6, 6, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 6, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 7}, + {6, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 8, 7}, + {7, 7, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 7, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 8, 8}, + }, + { + {8, 8, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 8}, + }, + { + {8, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 9, 9}, + }, + { + {9, 9, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 9}, + }, + { + {9, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 11, 10}, + {10, 10, 10, 10}, + {11, 10, 10, 10}, + }, + { + {10, 10, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 11}, + {10, 11, 10, 11}, + {11, 11, 11, 10}, + }, + { + {10, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 12, 11}, + {11, 11, 11, 11}, + {12, 11, 11, 11}, + }, + { + {11, 11, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 12, 12, 12}, + {12, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {13, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {13, 12, 13, 12}, + {12, 13, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 13}, + {13, 13, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 13, 13, 13}, + {13, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {14, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {14, 13, 14, 13}, + {13, 14, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 14, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 14, 14, 14}, + {14, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {15, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {15, 14, 15, 14}, + {14, 15, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 15, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 15, 15, 15}, + {15, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {16, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {16, 15, 16, 15}, + {15, 16, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 16, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 16, 16, 16}, + {16, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {17, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {17, 16, 17, 16}, + {16, 17, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 17, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 17, 17, 17}, + {17, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {18, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {18, 17, 18, 17}, + {17, 18, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 18, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 18, 18, 18}, + {18, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {19, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {19, 18, 19, 18}, + {18, 19, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 19}, + {19, 19, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 19, 19, 19}, + {19, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {20, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {20, 19, 20, 19}, + {19, 20, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 20, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 20, 20, 20}, + {19, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {21, 20, 21, 20}, + {20, 20, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 21, 21, 21}, + {20, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {22, 21, 22, 21}, + {21, 21, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 22}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 22, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {23, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 23}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 23, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 24}, + {23, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 25, 24}, + {24, 24, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 24, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 25}, + {24, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 26}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {25, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 26, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 27}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {26, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 27, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 28}, + {27, 28, 27, 28}, + {28, 28, 28, 27}, + }, + { + {27, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 29, 28}, + {28, 28, 28, 28}, + {29, 28, 28, 28}, + }, + { + {28, 28, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 29}, + {28, 29, 28, 29}, + {29, 29, 29, 28}, + }, + { + {28, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 29}, + }, + { + {29, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 30, 30}, + }, + { + {30, 30, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 30}, + }, + { + {30, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {31, 31, 31, 31}, + {31, 31, 32, 31}, + {31, 31, 31, 31}, + {32, 31, 31, 31}, + }, + { + {31, 31, 31, 32}, + {32, 31, 32, 31}, + {31, 32, 31, 31}, + {32, 31, 32, 31}, + }, + { + {31, 32, 31, 32}, + {32, 31, 32, 32}, + {31, 32, 31, 32}, + {32, 32, 32, 31}, + }, + { + {31, 32, 32, 32}, + {32, 32, 32, 32}, + {32, 32, 31, 32}, + {32, 32, 32, 32}, + }, + { + {32, 32, 32, 32}, + {32, 32, 33, 32}, + {32, 32, 32, 32}, + {33, 32, 32, 32}, + }, + { + {32, 32, 32, 33}, + {33, 32, 33, 32}, + {32, 33, 32, 32}, + {33, 32, 33, 32}, + }, + { + {32, 33, 32, 33}, + {33, 32, 33, 33}, + {32, 33, 32, 33}, + {33, 33, 33, 32}, + }, + { + {32, 33, 33, 33}, + {33, 33, 33, 33}, + {33, 33, 32, 33}, + {33, 33, 33, 33}, + }, + { + {33, 33, 33, 33}, + {33, 33, 34, 33}, + {33, 33, 33, 33}, + {34, 33, 33, 33}, + }, + { + {33, 33, 33, 34}, + {34, 33, 34, 33}, + {33, 34, 33, 33}, + {34, 33, 34, 33}, + }, + { + {33, 34, 33, 34}, + {34, 33, 34, 34}, + {33, 34, 33, 34}, + {34, 34, 34, 33}, + }, + { + {33, 34, 34, 34}, + {34, 34, 34, 34}, + {34, 34, 33, 34}, + {34, 34, 34, 34}, + }, + { + {34, 34, 34, 34}, + {34, 34, 35, 34}, + {34, 34, 34, 34}, + {35, 34, 34, 34}, + }, + { + {34, 34, 34, 35}, + {35, 34, 35, 34}, + {34, 35, 34, 34}, + {35, 34, 35, 34}, + }, + { + {34, 35, 34, 35}, + {35, 34, 35, 35}, + {34, 35, 34, 35}, + {35, 35, 35, 34}, + }, + { + {34, 35, 35, 35}, + {35, 35, 35, 35}, + {35, 35, 34, 35}, + {35, 35, 35, 35}, + }, + { + {35, 35, 35, 35}, + {35, 35, 36, 35}, + {35, 35, 35, 35}, + {36, 35, 35, 35}, + }, + { + {35, 35, 35, 36}, + {36, 35, 36, 35}, + {35, 36, 35, 35}, + {36, 35, 36, 35}, + }, + { + {35, 36, 35, 36}, + {36, 35, 36, 35}, + {35, 36, 35, 36}, + {36, 36, 36, 35}, + }, + { + {35, 36, 35, 36}, + {36, 36, 36, 36}, + {36, 36, 35, 36}, + {36, 36, 36, 36}, + }, + { + {36, 36, 36, 36}, + {36, 36, 36, 36}, + {36, 36, 36, 36}, + {37, 36, 36, 36}, + }, + { + {36, 36, 36, 36}, + {37, 36, 37, 36}, + {36, 37, 36, 36}, + {37, 36, 37, 36}, + }, + { + {36, 37, 36, 37}, + {37, 36, 37, 36}, + {36, 37, 36, 37}, + {37, 37, 37, 36}, + }, + { + {36, 37, 36, 37}, + {37, 37, 37, 37}, + {37, 37, 36, 37}, + {37, 37, 37, 37}, + }, + { + {37, 37, 37, 37}, + {37, 37, 37, 37}, + {37, 37, 37, 37}, + {38, 37, 37, 37}, + }, + { + {37, 37, 37, 37}, + {38, 37, 38, 37}, + {37, 38, 37, 37}, + {38, 37, 38, 37}, + }, + { + {37, 38, 37, 38}, + {38, 37, 38, 37}, + {37, 38, 37, 38}, + {38, 38, 38, 37}, + }, + { + {37, 38, 37, 38}, + {38, 38, 38, 38}, + {38, 38, 37, 38}, + {38, 38, 38, 38}, + }, + { + {38, 38, 38, 38}, + {38, 38, 38, 38}, + {38, 38, 38, 38}, + {39, 38, 38, 38}, + }, + { + {38, 38, 38, 38}, + {39, 38, 39, 38}, + {38, 39, 38, 38}, + {39, 38, 39, 38}, + }, + { + {38, 39, 38, 39}, + {39, 38, 39, 38}, + {38, 39, 38, 39}, + {39, 39, 39, 38}, + }, + { + {38, 39, 38, 39}, + {39, 39, 39, 39}, + {39, 39, 38, 39}, + {39, 39, 39, 39}, + }, + { + {39, 39, 39, 39}, + {39, 39, 39, 39}, + {39, 39, 39, 39}, + {40, 39, 39, 39}, + }, + { + {39, 39, 39, 39}, + {40, 39, 40, 39}, + {39, 40, 39, 39}, + {40, 39, 40, 39}, + }, + { + {39, 40, 39, 40}, + {40, 39, 40, 39}, + {39, 40, 39, 40}, + {40, 39, 40, 39}, + }, + { + {39, 40, 39, 40}, + {40, 40, 40, 40}, + {39, 40, 39, 40}, + {40, 40, 40, 40}, + }, + { + {40, 40, 40, 40}, + {40, 40, 40, 40}, + {40, 40, 40, 40}, + {40, 40, 40, 40}, + }, + { + {40, 40, 40, 40}, + {41, 40, 41, 40}, + {40, 40, 40, 40}, + {41, 40, 41, 40}, + }, + { + {40, 41, 40, 41}, + {41, 40, 41, 40}, + {40, 41, 40, 41}, + {41, 40, 41, 40}, + }, + { + {40, 41, 40, 41}, + {41, 41, 41, 41}, + {40, 41, 40, 41}, + {41, 41, 41, 41}, + }, + { + {41, 41, 41, 41}, + {41, 41, 41, 41}, + {41, 41, 41, 41}, + {41, 41, 41, 41}, + }, + { + {41, 41, 41, 41}, + {42, 41, 42, 41}, + {41, 41, 41, 41}, + {42, 41, 42, 41}, + }, + { + {41, 42, 41, 42}, + {42, 41, 42, 41}, + {41, 42, 41, 42}, + {42, 41, 42, 41}, + }, + { + {41, 42, 41, 42}, + {42, 42, 42, 42}, + {41, 42, 41, 42}, + {42, 42, 42, 42}, + }, + { + {42, 42, 42, 42}, + {42, 42, 42, 42}, + {42, 42, 42, 42}, + {42, 42, 42, 42}, + }, + { + {42, 42, 42, 42}, + {43, 42, 43, 42}, + {42, 42, 42, 42}, + {43, 42, 43, 42}, + }, + { + {42, 43, 42, 43}, + {43, 42, 43, 42}, + {42, 43, 42, 43}, + {43, 42, 43, 42}, + }, + { + {42, 43, 42, 43}, + {43, 43, 43, 43}, + {42, 43, 42, 43}, + {43, 43, 43, 43}, + }, + { + {43, 43, 43, 43}, + {43, 43, 43, 43}, + {43, 43, 43, 43}, + {43, 43, 43, 43}, + }, + { + {43, 43, 43, 43}, + {44, 43, 44, 43}, + {43, 43, 43, 43}, + {44, 43, 44, 43}, + }, + { + {43, 43, 43, 44}, + {44, 43, 44, 43}, + {43, 44, 43, 44}, + {44, 43, 44, 43}, + }, + { + {43, 44, 43, 44}, + {44, 43, 44, 44}, + {43, 44, 43, 44}, + {44, 44, 44, 44}, + }, + { + {43, 44, 44, 44}, + {44, 44, 44, 44}, + {44, 44, 44, 44}, + {44, 44, 44, 44}, + }, + { + {44, 44, 44, 44}, + {44, 44, 45, 44}, + {44, 44, 44, 44}, + {45, 44, 45, 44}, + }, + { + {44, 44, 44, 45}, + {45, 44, 45, 44}, + {44, 45, 44, 45}, + {45, 44, 45, 44}, + }, + { + {44, 45, 44, 45}, + {45, 44, 45, 45}, + {44, 45, 44, 45}, + {45, 45, 45, 45}, + }, + { + {44, 45, 45, 45}, + {45, 45, 45, 45}, + {45, 45, 45, 45}, + {45, 45, 45, 45}, + }, + { + {45, 45, 45, 45}, + {45, 45, 46, 45}, + {45, 45, 45, 45}, + {46, 45, 46, 45}, + }, + { + {45, 45, 45, 46}, + {46, 45, 46, 45}, + {45, 46, 45, 46}, + {46, 45, 46, 45}, + }, + { + {45, 46, 45, 46}, + {46, 45, 46, 46}, + {45, 46, 45, 46}, + {46, 46, 46, 46}, + }, + { + {45, 46, 46, 46}, + {46, 46, 46, 46}, + {46, 46, 46, 46}, + {46, 46, 46, 46}, + }, + { + {46, 46, 46, 46}, + {46, 46, 47, 46}, + {46, 46, 46, 46}, + {47, 46, 47, 46}, + }, + { + {46, 46, 46, 47}, + {47, 46, 47, 46}, + {46, 47, 46, 47}, + {47, 46, 47, 46}, + }, + { + {46, 47, 46, 47}, + {47, 46, 47, 47}, + {46, 47, 46, 47}, + {47, 47, 47, 47}, + }, + { + {46, 47, 47, 47}, + {47, 47, 47, 47}, + {47, 47, 47, 47}, + {47, 47, 47, 47}, + }, + { + {47, 47, 47, 47}, + {47, 47, 48, 47}, + {47, 47, 47, 47}, + {48, 47, 48, 47}, + }, + { + {47, 47, 47, 48}, + {48, 47, 48, 47}, + {47, 48, 47, 48}, + {48, 47, 48, 47}, + }, + { + {47, 48, 47, 48}, + {48, 47, 48, 48}, + {47, 48, 47, 48}, + {48, 48, 48, 48}, + }, + { + {47, 48, 48, 48}, + {48, 48, 48, 48}, + {48, 48, 48, 48}, + {48, 48, 48, 48}, + }, + { + {48, 48, 48, 48}, + {48, 48, 49, 48}, + {48, 48, 48, 48}, + {49, 48, 49, 48}, + }, + { + {48, 48, 48, 49}, + {49, 48, 49, 48}, + {48, 49, 48, 49}, + {49, 48, 49, 48}, + }, + { + {48, 49, 48, 49}, + {49, 48, 49, 49}, + {48, 49, 48, 49}, + {49, 49, 49, 49}, + }, + { + {48, 49, 49, 49}, + {49, 49, 49, 49}, + {49, 49, 49, 49}, + {49, 49, 49, 49}, + }, + { + {49, 49, 49, 49}, + {49, 49, 50, 49}, + {49, 49, 49, 49}, + {50, 49, 50, 49}, + }, + { + {49, 49, 49, 50}, + {50, 49, 50, 49}, + {49, 50, 49, 50}, + {50, 49, 50, 49}, + }, + { + {49, 50, 49, 50}, + {50, 49, 50, 50}, + {49, 50, 49, 50}, + {50, 50, 50, 50}, + }, + { + {49, 50, 50, 50}, + {50, 50, 50, 50}, + {50, 50, 50, 50}, + {50, 50, 50, 50}, + }, + { + {50, 50, 50, 50}, + {50, 50, 51, 50}, + {50, 50, 50, 50}, + {51, 50, 51, 50}, + }, + { + {50, 50, 50, 51}, + {51, 50, 51, 50}, + {50, 51, 50, 51}, + {51, 50, 51, 50}, + }, + { + {50, 51, 50, 51}, + {51, 50, 51, 51}, + {50, 51, 50, 51}, + {51, 51, 51, 51}, + }, + { + {50, 51, 51, 51}, + {51, 51, 51, 51}, + {51, 51, 51, 51}, + {51, 51, 51, 51}, + }, + { + {51, 51, 51, 51}, + {51, 51, 52, 51}, + {51, 51, 51, 51}, + {52, 51, 52, 51}, + }, + { + {51, 51, 51, 52}, + {52, 51, 52, 51}, + {51, 52, 51, 51}, + {52, 51, 52, 51}, + }, + { + {51, 52, 51, 52}, + {52, 51, 52, 52}, + {51, 52, 51, 52}, + {52, 52, 52, 51}, + }, + { + {51, 52, 52, 52}, + {52, 52, 52, 52}, + {52, 52, 51, 52}, + {52, 52, 52, 52}, + }, + { + {52, 52, 52, 52}, + {52, 52, 53, 52}, + {52, 52, 52, 52}, + {53, 52, 52, 52}, + }, + { + {52, 52, 52, 53}, + {53, 52, 53, 52}, + {52, 53, 52, 52}, + {53, 52, 53, 52}, + }, + { + {52, 53, 52, 53}, + {53, 52, 53, 53}, + {52, 53, 52, 53}, + {53, 53, 53, 52}, + }, + { + {52, 53, 53, 53}, + {53, 53, 53, 53}, + {53, 53, 52, 53}, + {53, 53, 53, 53}, + }, + { + {53, 53, 53, 53}, + {53, 53, 54, 53}, + {53, 53, 53, 53}, + {54, 53, 53, 53}, + }, + { + {53, 53, 53, 54}, + {54, 53, 54, 53}, + {53, 54, 53, 53}, + {54, 53, 54, 53}, + }, + { + {53, 54, 53, 54}, + {54, 53, 54, 54}, + {53, 54, 53, 54}, + {54, 54, 54, 53}, + }, + { + {53, 54, 54, 54}, + {54, 54, 54, 54}, + {54, 54, 53, 54}, + {54, 54, 54, 54}, + }, + { + {54, 54, 54, 54}, + {54, 54, 55, 54}, + {54, 54, 54, 54}, + {55, 54, 54, 54}, + }, + { + {54, 54, 54, 55}, + {55, 54, 55, 54}, + {54, 55, 54, 54}, + {55, 54, 55, 54}, + }, + { + {54, 55, 54, 55}, + {55, 54, 55, 55}, + {54, 55, 54, 55}, + {55, 55, 55, 54}, + }, + { + {54, 55, 55, 55}, + {55, 55, 55, 55}, + {55, 55, 54, 55}, + {55, 55, 55, 55}, + }, + { + {55, 55, 55, 55}, + {55, 55, 56, 55}, + {55, 55, 55, 55}, + {56, 55, 55, 55}, + }, + { + {55, 55, 55, 55}, + {56, 55, 56, 55}, + {55, 56, 55, 55}, + {56, 55, 56, 55}, + }, + { + {55, 56, 55, 56}, + {56, 55, 56, 55}, + {55, 56, 55, 56}, + {56, 56, 56, 55}, + }, + { + {55, 56, 55, 56}, + {56, 56, 56, 56}, + {56, 56, 55, 56}, + {56, 56, 56, 56}, + }, + { + {56, 56, 56, 56}, + {56, 56, 56, 56}, + {56, 56, 56, 56}, + {57, 56, 56, 56}, + }, + { + {56, 56, 56, 56}, + {57, 56, 57, 56}, + {56, 57, 56, 56}, + {57, 56, 57, 56}, + }, + { + {56, 57, 56, 57}, + {57, 56, 57, 56}, + {56, 57, 56, 57}, + {57, 57, 57, 56}, + }, + { + {56, 57, 56, 57}, + {57, 57, 57, 57}, + {57, 57, 56, 57}, + {57, 57, 57, 57}, + }, + { + {57, 57, 57, 57}, + {57, 57, 57, 57}, + {57, 57, 57, 57}, + {58, 57, 57, 57}, + }, + { + {57, 57, 57, 57}, + {58, 57, 58, 57}, + {57, 58, 57, 57}, + {58, 57, 58, 57}, + }, + { + {57, 58, 57, 58}, + {58, 57, 58, 57}, + {57, 58, 57, 58}, + {58, 58, 58, 57}, + }, + { + {57, 58, 57, 58}, + {58, 58, 58, 58}, + {58, 58, 57, 58}, + {58, 58, 58, 58}, + }, + { + {58, 58, 58, 58}, + {58, 58, 58, 58}, + {58, 58, 58, 58}, + {59, 58, 58, 58}, + }, + { + {58, 58, 58, 58}, + {59, 58, 59, 58}, + {58, 59, 58, 58}, + {59, 58, 59, 58}, + }, + { + {58, 59, 58, 59}, + {59, 58, 59, 58}, + {58, 59, 58, 59}, + {59, 59, 59, 58}, + }, + { + {58, 59, 58, 59}, + {59, 59, 59, 59}, + {59, 59, 58, 59}, + {59, 59, 59, 59}, + }, + { + {59, 59, 59, 59}, + {59, 59, 59, 59}, + {59, 59, 59, 59}, + {60, 59, 59, 59}, + }, + { + {59, 59, 59, 59}, + {60, 59, 60, 59}, + {59, 59, 59, 59}, + {60, 59, 60, 59}, + }, + { + {59, 60, 59, 60}, + {60, 59, 60, 59}, + {59, 60, 59, 60}, + {60, 59, 60, 59}, + }, + { + {59, 60, 59, 60}, + {60, 60, 60, 60}, + {59, 60, 59, 60}, + {60, 60, 60, 60}, + }, + { + {60, 60, 60, 60}, + {60, 60, 60, 60}, + {60, 60, 60, 60}, + {60, 60, 60, 60}, + }, + { + {60, 60, 60, 60}, + {61, 60, 61, 60}, + {60, 60, 60, 60}, + {61, 60, 61, 60}, + }, + { + {60, 61, 60, 61}, + {61, 60, 61, 60}, + {60, 61, 60, 61}, + {61, 60, 61, 60}, + }, + { + {60, 61, 60, 61}, + {61, 61, 61, 61}, + {60, 61, 60, 61}, + {61, 61, 61, 61}, + }, + { + {61, 61, 61, 61}, + {61, 61, 61, 61}, + {61, 61, 61, 61}, + {61, 61, 61, 61}, + }, + { + {61, 61, 61, 61}, + {62, 61, 62, 61}, + {61, 61, 61, 61}, + {62, 61, 62, 61}, + }, + { + {61, 62, 61, 62}, + {62, 61, 62, 61}, + {61, 62, 61, 62}, + {62, 61, 62, 61}, + }, + { + {61, 62, 61, 62}, + {62, 62, 62, 62}, + {61, 62, 61, 62}, + {62, 62, 62, 62}, + }, + { + {62, 62, 62, 62}, + {62, 62, 62, 62}, + {62, 62, 62, 62}, + {62, 62, 62, 62}, + }, + { + {62, 62, 62, 62}, + {63, 62, 63, 62}, + {62, 62, 62, 62}, + {63, 62, 63, 62}, + }, + { + {62, 63, 62, 63}, + {63, 62, 63, 62}, + {62, 63, 62, 63}, + {63, 62, 63, 62}, + }, + { + {62, 63, 62, 63}, + {63, 63, 63, 63}, + {62, 63, 62, 63}, + {63, 63, 63, 63}, + }, + { + {63, 63, 63, 63}, + {63, 63, 63, 63}, + {63, 63, 63, 63}, + {63, 63, 63, 63}, + }, +}; + +uint8_t dither_rb2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, +}; + +uint8_t dither_g2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, + { + {31, 31}, + {32, 31}, + }, + { + {31, 32}, + {32, 31}, + }, + { + {31, 32}, + {32, 32}, + }, + { + {32, 32}, + {32, 32}, + }, + { + {32, 32}, + {33, 32}, + }, + { + {32, 33}, + {33, 32}, + }, + { + {32, 33}, + {33, 33}, + }, + { + {33, 33}, + {33, 33}, + }, + { + {33, 33}, + {34, 33}, + }, + { + {33, 34}, + {34, 33}, + }, + { + {33, 34}, + {34, 34}, + }, + { + {34, 34}, + {34, 34}, + }, + { + {34, 34}, + {35, 34}, + }, + { + {34, 35}, + {35, 34}, + }, + { + {34, 35}, + {35, 35}, + }, + { + {35, 35}, + {35, 35}, + }, + { + {35, 35}, + {36, 35}, + }, + { + {35, 36}, + {36, 35}, + }, + { + {35, 36}, + {36, 35}, + }, + { + {35, 36}, + {36, 36}, + }, + { + {36, 36}, + {36, 36}, + }, + { + {36, 36}, + {37, 36}, + }, + { + {36, 37}, + {37, 36}, + }, + { + {36, 37}, + {37, 37}, + }, + { + {37, 37}, + {37, 37}, + }, + { + {37, 37}, + {38, 37}, + }, + { + {37, 38}, + {38, 37}, + }, + { + {37, 38}, + {38, 38}, + }, + { + {38, 38}, + {38, 38}, + }, + { + {38, 38}, + {39, 38}, + }, + { + {38, 39}, + {39, 38}, + }, + { + {38, 39}, + {39, 39}, + }, + { + {39, 39}, + {39, 39}, + }, + { + {39, 39}, + {40, 39}, + }, + { + {39, 40}, + {40, 39}, + }, + { + {39, 40}, + {40, 40}, + }, + { + {40, 40}, + {40, 40}, + }, + { + {40, 40}, + {41, 40}, + }, + { + {40, 41}, + {41, 40}, + }, + { + {40, 41}, + {41, 41}, + }, + { + {41, 41}, + {41, 41}, + }, + { + {41, 41}, + {42, 41}, + }, + { + {41, 42}, + {42, 41}, + }, + { + {41, 42}, + {42, 42}, + }, + { + {42, 42}, + {42, 42}, + }, + { + {42, 42}, + {43, 42}, + }, + { + {42, 43}, + {43, 42}, + }, + { + {42, 43}, + {43, 43}, + }, + { + {43, 43}, + {43, 43}, + }, + { + {43, 43}, + {44, 43}, + }, + { + {43, 44}, + {44, 43}, + }, + { + {43, 44}, + {44, 44}, + }, + { + {44, 44}, + {44, 44}, + }, + { + {44, 44}, + {45, 44}, + }, + { + {44, 45}, + {45, 44}, + }, + { + {44, 45}, + {45, 45}, + }, + { + {45, 45}, + {45, 45}, + }, + { + {45, 45}, + {46, 45}, + }, + { + {45, 46}, + {46, 45}, + }, + { + {45, 46}, + {46, 46}, + }, + { + {46, 46}, + {46, 46}, + }, + { + {46, 46}, + {47, 46}, + }, + { + {46, 47}, + {47, 46}, + }, + { + {46, 47}, + {47, 47}, + }, + { + {47, 47}, + {47, 47}, + }, + { + {47, 47}, + {48, 47}, + }, + { + {47, 48}, + {48, 47}, + }, + { + {47, 48}, + {48, 48}, + }, + { + {48, 48}, + {48, 48}, + }, + { + {48, 48}, + {49, 48}, + }, + { + {48, 49}, + {49, 48}, + }, + { + {48, 49}, + {49, 49}, + }, + { + {49, 49}, + {49, 49}, + }, + { + {49, 49}, + {50, 49}, + }, + { + {49, 50}, + {50, 49}, + }, + { + {49, 50}, + {50, 50}, + }, + { + {50, 50}, + {50, 50}, + }, + { + {50, 50}, + {51, 50}, + }, + { + {50, 51}, + {51, 50}, + }, + { + {50, 51}, + {51, 51}, + }, + { + {51, 51}, + {51, 51}, + }, + { + {51, 51}, + {52, 51}, + }, + { + {51, 52}, + {52, 51}, + }, + { + {51, 52}, + {52, 52}, + }, + { + {52, 52}, + {52, 52}, + }, + { + {52, 52}, + {53, 52}, + }, + { + {52, 53}, + {53, 52}, + }, + { + {52, 53}, + {53, 53}, + }, + { + {53, 53}, + {53, 53}, + }, + { + {53, 53}, + {54, 53}, + }, + { + {53, 54}, + {54, 53}, + }, + { + {53, 54}, + {54, 54}, + }, + { + {54, 54}, + {54, 54}, + }, + { + {54, 54}, + {55, 54}, + }, + { + {54, 55}, + {55, 54}, + }, + { + {54, 55}, + {55, 55}, + }, + { + {55, 55}, + {55, 55}, + }, + { + {55, 55}, + {56, 55}, + }, + { + {55, 55}, + {56, 55}, + }, + { + {55, 56}, + {56, 55}, + }, + { + {55, 56}, + {56, 56}, + }, + { + {56, 56}, + {56, 56}, + }, + { + {56, 56}, + {57, 56}, + }, + { + {56, 57}, + {57, 56}, + }, + { + {56, 57}, + {57, 57}, + }, + { + {57, 57}, + {57, 57}, + }, + { + {57, 57}, + {58, 57}, + }, + { + {57, 58}, + {58, 57}, + }, + { + {57, 58}, + {58, 58}, + }, + { + {58, 58}, + {58, 58}, + }, + { + {58, 58}, + {59, 58}, + }, + { + {58, 59}, + {59, 58}, + }, + { + {58, 59}, + {59, 59}, + }, + { + {59, 59}, + {59, 59}, + }, + { + {59, 59}, + {60, 59}, + }, + { + {59, 60}, + {60, 59}, + }, + { + {59, 60}, + {60, 60}, + }, + { + {60, 60}, + {60, 60}, + }, + { + {60, 60}, + {61, 60}, + }, + { + {60, 61}, + {61, 60}, + }, + { + {60, 61}, + {61, 61}, + }, + { + {61, 61}, + {61, 61}, + }, + { + {61, 61}, + {62, 61}, + }, + { + {61, 62}, + {62, 61}, + }, + { + {61, 62}, + {62, 62}, + }, + { + {62, 62}, + {62, 62}, + }, + { + {62, 62}, + {63, 62}, + }, + { + {62, 63}, + {63, 62}, + }, + { + {62, 63}, + {63, 63}, + }, + { + {63, 63}, + {63, 63}, + }, +}; + diff --git a/src/video.c b/src/video.c new file mode 100644 index 000000000..40d6540df --- /dev/null +++ b/src/video.c @@ -0,0 +1,495 @@ +#include +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "io.h" +#include "cpu.h" +#include "rom.h" +#include "timer.h" + +#include "vid_ati18800.h" +#include "vid_ati28800.h" +#include "vid_ati_mach64.h" +#include "vid_cga.h" +#include "vid_cl5429.h" +#include "vid_ega.h" +#include "vid_et4000.h" +#include "vid_et4000w32.h" +#include "vid_hercules.h" +#include "vid_mda.h" +#include "vid_olivetti_m24.h" +#include "vid_oti067.h" +#include "vid_paradise.h" +#include "vid_pc1512.h" +#include "vid_pc1640.h" +#include "vid_pc200.h" +#include "vid_pcjr.h" +#include "vid_ps1_svga.h" +#include "vid_s3.h" +#include "vid_s3_virge.h" +#include "vid_tandy.h" +#include "vid_tandysl.h" +#include "vid_tgui9440.h" +#include "vid_tvga.h" +#include "vid_vga.h" + +typedef struct +{ + char name[64]; + device_t *device; + int legacy_id; +} VIDEO_CARD; + +static VIDEO_CARD video_cards[] = +{ + {"ATI Graphics Pro Turbo (Mach64 GX)", &mach64gx_device, GFX_MACH64GX}, + {"ATI VGA Charger (ATI-28800)", &ati28800_device, GFX_VGACHARGER}, + {"ATI VGA Edge-16 (ATI-18800)", &ati18800_device, GFX_VGAEDGE16}, + {"Cardex Tseng ET4000/w32p", &et4000w32pc_device, GFX_ET4000W32C}, + {"CGA (New)", &cga_new_device, GFX_NEW_CGA}, + {"CGA (Old)", &cga_device, GFX_CGA}, + {"Cirrus Logic CL-GD5429", &gd5429_device, GFX_CL_GD5429}, + {"Diamond Stealth 32 (Tseng ET4000/w32p)", &et4000w32p_device, GFX_ET4000W32}, + {"Diamond Stealth 3D 2000 (S3 ViRGE)", &s3_virge_device, GFX_VIRGE}, + {"EGA", &ega_device, GFX_EGA}, + {"Chips & Technologies SuperEGA", &sega_device, GFX_SUPER_EGA}, + {"Compaq ATI VGA Wonder XL (ATI-28800)", &compaq_ati28800_device, GFX_VGAWONDERXL}, + {"Compaq EGA", &cpqega_device, GFX_COMPAQ_EGA}, + {"Compaq/Paradise VGA", &cpqvga_device, GFX_COMPAQ_VGA}, + {"Hercules", &hercules_device, GFX_HERCULES}, + {"Hercules InColor", &hercules_device, GFX_INCOLOR}, + {"MDA", &mda_device, GFX_MDA}, + {"Miro Crystal S3 Vision964", &s3_miro_vision964_device, GFX_MIRO_VISION964}, + {"Number Nine 9FX (S3 Trio64)", &s3_9fx_device, GFX_N9_9FX}, + {"OAK OTI-067", &oti067_device, GFX_OTI067}, + {"OAK OTI-077", &oti077_device, GFX_OTI077}, + {"Paradise Bahamas 64 (S3 Vision864)", &s3_bahamas64_device, GFX_BAHAMAS64}, + {"Paradise WD90C11", ¶dise_wd90c11_device, GFX_WD90C11}, + {"Phoenix S3 Trio32", &s3_phoenix_trio32_device, GFX_PHOENIX_TRIO32}, + {"Phoenix S3 Trio64", &s3_phoenix_trio64_device, GFX_PHOENIX_TRIO64}, + {"S3 ViRGE/DX", &s3_virge_375_device, GFX_VIRGEDX}, + {"Trident TVGA8900D", &tvga8900d_device, GFX_TVGA}, + {"Tseng ET4000AX", &et4000_device, GFX_ET4000}, + {"Trident TGUI9440", &tgui9440_device, GFX_TGUI9440}, + {"VGA", &vga_device, GFX_VGA}, + {"", NULL, 0} +}; + +int video_card_available(int card) +{ + if (video_cards[card].device) + return device_available(video_cards[card].device); + + return 1; +} + +char *video_card_getname(int card) +{ + return video_cards[card].name; +} + +device_t *video_card_getdevice(int card) +{ + return video_cards[card].device; +} + +int video_card_has_config(int card) +{ + return video_cards[card].device->config ? 1 : 0; +} + +int video_card_getid(char *s) +{ + int c = 0; + + while (video_cards[c].device) + { + if (!strcmp(video_cards[c].name, s)) + return c; + c++; + } + + return 0; +} + +int video_old_to_new(int card) +{ + int c = 0; + + while (video_cards[c].device) + { + if (video_cards[c].legacy_id == card) + return c; + c++; + } + + return 0; +} + +int video_new_to_old(int card) +{ + return video_cards[card].legacy_id; +} + +int video_fullscreen = 0, video_fullscreen_scale, video_fullscreen_first; +uint32_t *video_15to32, *video_16to32; + +int egareads=0,egawrites=0; +int changeframecount=2; + +uint8_t rotatevga[8][256]; + +int frames = 0; + +int fullchange; + +uint8_t edatlookup[4][4]; + +int enable_overscan; +int overscan_x, overscan_y; +int force_43; +int enable_flash; + +/*Video timing settings - + +8-bit - 1mb/sec + B = 8 ISA clocks + W = 16 ISA clocks + L = 32 ISA clocks + +Slow 16-bit - 2mb/sec + B = 6 ISA clocks + W = 8 ISA clocks + L = 16 ISA clocks + +Fast 16-bit - 4mb/sec + B = 3 ISA clocks + W = 3 ISA clocks + L = 6 ISA clocks + +Slow VLB/PCI - 8mb/sec (ish) + B = 4 bus clocks + W = 8 bus clocks + L = 16 bus clocks + +Mid VLB/PCI - + B = 4 bus clocks + W = 5 bus clocks + L = 10 bus clocks + +Fast VLB/PCI - + B = 3 bus clocks + W = 3 bus clocks + L = 4 bus clocks +*/ + +enum +{ + VIDEO_ISA = 0, + VIDEO_BUS +}; + +int video_speed = 0; +int video_timing[6][4] = +{ + {VIDEO_ISA, 8, 16, 32}, + {VIDEO_ISA, 6, 8, 16}, + {VIDEO_ISA, 3, 3, 6}, + {VIDEO_BUS, 4, 8, 16}, + {VIDEO_BUS, 4, 5, 10}, + {VIDEO_BUS, 3, 3, 4} +}; + +void video_updatetiming() +{ + if (video_timing[video_speed][0] == VIDEO_ISA) + { + video_timing_b = (int)(isa_timing * video_timing[video_speed][1]); + video_timing_w = (int)(isa_timing * video_timing[video_speed][2]); + video_timing_l = (int)(isa_timing * video_timing[video_speed][3]); + } + else + { + video_timing_b = (int)(bus_timing * video_timing[video_speed][1]); + video_timing_w = (int)(bus_timing * video_timing[video_speed][2]); + video_timing_l = (int)(bus_timing * video_timing[video_speed][3]); + } + if (cpu_16bitbus) + video_timing_l = video_timing_w * 2; +} + +int video_timing_b, video_timing_w, video_timing_l; + +int video_res_x, video_res_y, video_bpp; + +void (*video_blit_memtoscreen)(int x, int y, int y1, int y2, int w, int h); +void (*video_blit_memtoscreen_8)(int x, int y, int w, int h); + +void video_init() +{ + pclog("Video_init %i %i\n",romset,gfxcard); + + switch (romset) + { + case ROM_IBMPCJR: + device_add(&pcjr_video_device); + return; + + case ROM_TANDY: + case ROM_TANDY1000HX: + device_add(&tandy_device); + return; + + case ROM_TANDY1000SL2: + device_add(&tandysl_device); + return; + + case ROM_PC1512: + device_add(&pc1512_device); + return; + + case ROM_PC1640: + device_add(&pc1640_device); + return; + + case ROM_PC200: + device_add(&pc200_device); + return; + + case ROM_OLIM24: + device_add(&m24_device); + return; + + case ROM_PC2086: + device_add(¶dise_pvga1a_pc2086_device); + return; + + case ROM_PC3086: + device_add(¶dise_pvga1a_pc3086_device); + return; + + case ROM_MEGAPC: + device_add(¶dise_wd90c11_megapc_device); + return; + + case ROM_ACER386: + device_add(&oti067_device); + return; + + case ROM_IBMPS1_2011: + device_add(&ps1vga_device); + return; + + case ROM_IBMPS1_2121: + device_add(&ps1_m2121_svga_device); + return; + } + device_add(video_cards[video_old_to_new(gfxcard)].device); +} + + +BITMAP *buffer, *buffer32; + +uint8_t fontdat[256][8]; +uint8_t fontdatm[256][16]; + +int xsize=1,ysize=1; + +PALETTE cgapal; + +void loadfont(char *s, int format) +{ + FILE *f=romfopen(s,"rb"); + int c,d; + if (!f) + return; + + if (!format) + { + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d]=getc(f); + } + } + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d+8]=getc(f); + } + } + fseek(f,4096+2048,SEEK_SET); + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdat[c][d]=getc(f); + } + } + } + else if (format == 1) + { + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d]=getc(f); + } + } + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d+8]=getc(f); + } + } + fseek(f, 4096, SEEK_SET); + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdat[c][d]=getc(f); + } + for (d=0;d<8;d++) getc(f); + } + } + else + { + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdat[c][d]=getc(f); + } + } + } + fclose(f); +} + + +void initvideo() +{ + int c, d, e; + + /* Account for overscan. */ + buffer32 = create_bitmap(2064, 2056); + + buffer = create_bitmap(2064, 2056); + + for (c = 0; c < 64; c++) + { + cgapal[c + 64].r = (((c & 4) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].b = (((c & 1) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + if ((c & 0x17) == 6) + cgapal[c + 64].g >>= 1; + } + for (c = 0; c < 64; c++) + { + cgapal[c + 128].r = (((c & 4) ? 2 : 0) | ((c & 0x20) ? 1 : 0)) * 21; + cgapal[c + 128].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 128].b = (((c & 1) ? 2 : 0) | ((c & 0x08) ? 1 : 0)) * 21; + } + + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + rotatevga[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + for (c = 0; c < 4; c++) + { + for (d = 0; d < 4; d++) + { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; +// printf("Edat %i,%i now %02X\n",c,d,edatlookup[c][d]); + } + } + + video_15to32 = malloc(4 * 65536); + for (c = 0; c < 65536; c++) + video_15to32[c] = ((c & 31) << 3) | (((c >> 5) & 31) << 11) | (((c >> 10) & 31) << 19); + + video_16to32 = malloc(4 * 65536); + for (c = 0; c < 65536; c++) + video_16to32[c] = ((c & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 11) & 31) << 19); + +} + +void closevideo() +{ + free(video_15to32); + free(video_16to32); + destroy_bitmap(buffer); + destroy_bitmap(buffer32); +} + +#ifdef __unix +void d3d_fs_take_screenshot(char *fn) +{ +} + +void d3d_take_screenshot(char *fn) +{ +} + +void ddraw_fs_take_screenshot(char *fn) +{ +} + +void ddraw_take_screenshot(char *fn) +{ +} + +void take_screenshot() +{ +} +#else +void take_screenshot() +{ + char fn[1024]; + time_t now = time(0); + if ((vid_api < 0) || (vid_api > 1)) return; + memset(fn, 0, 1024); + pclog("Video API is: %i\n", vid_api); + if (vid_api == 1) + { + strftime(fn, 1024, "screenshots/%Y%m%d_%H%M%S.png", localtime(&now)); + if (video_fullscreen) + { + d3d_fs_take_screenshot(fn); + } + else + { + pclog("Direct 3D...\n"); + d3d_take_screenshot(fn); + } + } + else if (vid_api == 0) + { + strftime(fn, 1024, "screenshots/%Y%m%d_%H%M%S.bmp", localtime(&now)); + if (video_fullscreen) + { + ddraw_fs_take_screenshot(fn); + } + else + { + ddraw_take_screenshot(fn); + } + } +} +#endif diff --git a/src/video.h b/src/video.h new file mode 100644 index 000000000..6c411cf8e --- /dev/null +++ b/src/video.h @@ -0,0 +1,105 @@ +#ifdef __unix + +#include "allegro-main.h" + +#else + +typedef struct +{ + int w, h; + uint8_t *dat; + uint8_t *line[0]; +} BITMAP; + +extern BITMAP *screen; + +BITMAP *create_bitmap(int w, int h); + +typedef struct +{ + uint8_t r, g, b; +} RGB; + +typedef RGB PALETTE[256]; + +#define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) +#define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + +#endif + +extern BITMAP *buffer, *buffer32; + +int video_card_available(int card); +char *video_card_getname(int card); +struct device_t *video_card_getdevice(int card); +int video_card_has_config(int card); +int video_card_getid(char *s); +int video_old_to_new(int card); +int video_new_to_old(int card); + +extern int video_fullscreen, video_fullscreen_scale, video_fullscreen_first; + +enum +{ + FULLSCR_SCALE_FULL = 0, + FULLSCR_SCALE_43, + FULLSCR_SCALE_SQ, + FULLSCR_SCALE_INT +}; + +extern int egareads,egawrites; + +extern int fullchange; +extern int changeframecount; + +extern uint8_t fontdat[256][8]; +extern uint8_t fontdatm[256][16]; + +extern uint32_t *video_15to32, *video_16to32; + +extern int xsize,ysize; + +extern float cpuclock; + +extern int emu_fps, frames; + +extern int readflash; + +extern void (*video_recalctimings)(); + +extern void (*video_blit_memtoscreen)(int x, int y, int y1, int y2, int w, int h); +extern void (*video_blit_memtoscreen_8)(int x, int y, int w, int h); + +/* Enable EGA/(S)VGA overscan border. */ +extern int enable_overscan; +extern int overscan_x, overscan_y; +/* Forcibly stretch emulated video output to 4:3 or not. */ +extern int force_43; +/* Enable CGA brown circuitry. */ +extern int cga_brown; +/* Enable CGA color burst. */ +extern int cga_color_burst; +/* Enable disk activity flash. */ +extern int enable_flash; + +extern int video_timing_b, video_timing_w, video_timing_l; +extern int video_speed; + +extern int video_res_x, video_res_y, video_bpp; + +extern int vid_resize; + +extern int winsizex,winsizey; + +#ifdef __cplusplus +extern "C" { +#endif +void take_screenshot(); + +void d3d_take_screenshot(char *fn); +void d3d_fs_take_screenshot(char *fn); +void ddraw_take_screenshot(char *fn); +void ddraw_fs_take_screenshot(char *fn); +#ifdef __cplusplus +} +#endif diff --git a/src/w83877f.c b/src/w83877f.c new file mode 100644 index 000000000..d94fdfa3b --- /dev/null +++ b/src/w83877f.c @@ -0,0 +1,520 @@ +/* + Winbond W83877F Super I/O Chip + Used by the Award 430HX +*/ + +#include "ibm.h" + +#include "fdc.h" +#include "fdd.h" +#include "disc.h" +#include "io.h" +#include "lpt.h" +// #include "mouse_serial.h" +#include "serial.h" +#include "w83877f.h" + +static int w83877f_locked; +static int w83877f_rw_locked = 0; +static int w83877f_curreg = 0; +static uint8_t w83877f_regs[0x2A]; +static uint8_t tries; + +static int winbond_port = 0x3f0; +static int winbond_key = 0x89; +static int winbond_key_times = 1; + +void w83877f_write(uint16_t port, uint8_t val, void *priv); +uint8_t w83877f_read(uint16_t port, void *priv); + +#define OCSS0 (w83877f_regs[0] & 1) +#define OCSS1 ((w83877f_regs[0] >> 1) & 1) +#define PRTMODS0 ((w83877f_regs[0] >> 2) & 1) +#define PRTMODS1 ((w83877f_regs[0] >> 3) & 1) + +#define ABCHG (w83877f_regs[1] >> 7) + +#define CEA (w83877f_regs[2] & 1) +#define EA3 ((w83877f_regs[2] >> 1) & 1) +#define EA4 ((w83877f_regs[2] >> 2) & 1) +#define EA5 ((w83877f_regs[2] >> 3) & 1) +#define EA6 ((w83877f_regs[2] >> 4) & 1) +#define EA7 ((w83877f_regs[2] >> 5) & 1) +#define EA8 ((w83877f_regs[2] >> 6) & 1) +#define EA9 (w83877f_regs[2] >> 7) + +#define SUBMIDI (w83877f_regs[3] & 1) +#define SUAMIDI ((w83877f_regs[3] >> 1) & 1) +#define GMODS ((w83877f_regs[3] >> 4) & 1) +#define EPPVER ((w83877f_regs[3] >> 5) & 1) +#define GMENL ((w83877f_regs[3] >> 6) & 1) + +#define URBTRI (w83877f_regs[4] & 1) +#define URATRI ((w83877f_regs[4] >> 1) & 1) +#define GMTRI ((w83877f_regs[4] >> 2) & 1) +#define PRTTRI ((w83877f_regs[4] >> 3) & 1) +#define URBPWD ((w83877f_regs[4] >> 4) & 1) +#define URAPWD ((w83877f_regs[4] >> 5) & 1) +#define GMPWD ((w83877f_regs[4] >> 6) & 1) +#define PRTPWD (w83877f_regs[4] >> 7) + +#define ECPFTHR0 (w83877f_regs[5] & 1) +#define ECPFTHR1 ((w83877f_regs[5] >> 1) & 1) +#define ECPFTHR2 ((w83877f_regs[5] >> 2) & 1) +#define ECPFTHR3 ((w83877f_regs[5] >> 3) & 1) + +#define IDETRI (w83877f_regs[6] & 1) +#define FDCTRI ((w83877f_regs[6] >> 1) & 1) +#define IDEPWD ((w83877f_regs[6] >> 2) & 1) +#define FDCPWD ((w83877f_regs[6] >> 3) & 1) +#define FIPURDWM ((w83877f_regs[6] >> 4) & 1) +#define SEL4FDD ((w83877f_regs[6] >> 5) & 1) +#define OSCS2 ((w83877f_regs[6] >> 6) & 1) + +#define FDDA_TYPE (w83877f_regs[7] & 3) +#define FDDB_TYPE ((w83877f_regs[7] >> 2) & 3) +#define FDDC_TYPE ((w83877f_regs[7] >> 4) & 3) +#define FDDD_TYPE ((w83877f_regs[7] >> 6) & 3) + +#define FD_BOOT (w83877f_regs[8] & 3) +#define MEDIA_ID ((w83877f_regs[8] >> 2) & 3) +#define SWWP ((w83877f_regs[8] >> 4) & 1) +#define DISFDDWR ((w83877f_regs[8] >> 5) & 1) +#define APDTMS2 ((w83877f_regs[8] >> 6) & 1) +#define APDTMS1 (w83877f_regs[8] >> 7) + +#define CHIP_ID (w83877f_regs[9] & 0xF) +#define EN3MODE ((w83877f_regs[9] >> 5) & 1) +#define LOCKREG ((w83877f_regs[9] >> 6) & 1) +#define PRTMODS2 ((w83877f_regs[9] >> 7) & 1) + +#define PEXTECPP (w83877f_regs[0xA] & 1) +#define PEXT_ECP ((w83877f_regs[0xA] >> 1) & 1) +#define PEXT_EPP ((w83877f_regs[0xA] >> 2) & 1) +#define PEXT_ADP ((w83877f_regs[0xA] >> 3) & 1) +#define PDCACT ((w83877f_regs[0xA] >> 4) & 1) +#define PDIRHOP ((w83877f_regs[0xA] >> 5) & 1) +#define PEXT_ACT ((w83877f_regs[0xA] >> 6) & 1) +#define PFDCACT (w83877f_regs[0xA] >> 7) + +#define DRV2EN_NEG (w83877f_regs[0xB] & 1) /* 0 = drive 2 installed */ +#define INVERTZ ((w83877f_regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */ +#define MFM ((w83877f_regs[0xB] >> 2) & 1) +#define IDENT ((w83877f_regs[0xB] >> 3) & 1) +#define ENIFCHG ((w83877f_regs[0xB] >> 4) & 1) + +#define TX2INV (w83877f_regs[0xC] & 1) +#define RX2INV ((w83877f_regs[0xC] >> 1) & 1) +#define URIRSEL ((w83877f_regs[0xC] >> 3) & 1) +#define HEFERE ((w83877f_regs[0xC] >> 5) & 1) +#define TURB ((w83877f_regs[0xC] >> 6) & 1) +#define TURA (w83877f_regs[0xC] >> 7) + +#define IRMODE0 (w83877f_regs[0xD] & 1) +#define IRMODE1 ((w83877f_regs[0xD] >> 1) & 1) +#define IRMODE2 ((w83877f_regs[0xD] >> 2) & 1) +#define HDUPLX ((w83877f_regs[0xD] >> 3) & 1) +#define SIRRX0 ((w83877f_regs[0xD] >> 4) & 1) +#define SIRRX1 ((w83877f_regs[0xD] >> 5) & 1) +#define SIRTX0 ((w83877f_regs[0xD] >> 6) & 1) +#define SIRTX1 (w83877f_regs[0xD] >> 7) + +#define GIO0AD (w83877f_regs[0x10] | (((uint16_t) w83877f_regs[0x10] & 7) << 8)) +#define GIO0CADM (w83877f_regs[0x11] >> 6) +#define GIO1AD (w83877f_regs[0x12] | (((uint16_t) w83877f_regs[0x13] & 7) << 8)) +#define GIO1CADM (w83877f_regs[0x13] >> 6) + +#define GDA0IPI (w83877f_regs[0x14] & 1) +#define GDA0OPI ((w83877f_regs[0x14] >> 1) & 1) +#define GCS0IOW ((w83877f_regs[0x14] >> 2) & 1) +#define GCS0IOR ((w83877f_regs[0x14] >> 3) & 1) +#define GIO0CSH ((w83877f_regs[0x14] >> 4) & 1) +#define GIOP0MD ((w83877f_regs[0x14] >> 5) & 7) + +#define GDA1IPI (w83877f_regs[0x15] & 1) +#define GDA1OPI ((w83877f_regs[0x15] >> 1) & 1) +#define GCS1IOW ((w83877f_regs[0x15] >> 2) & 1) +#define GCS1IOR ((w83877f_regs[0x15] >> 3) & 1) +#define GIO1CSH ((w83877f_regs[0x15] >> 4) & 1) +#define GIOP1MD ((w83877f_regs[0x15] >> 5) & 7) + +#define HEFRAS (w83877f_regs[0x16] & 1) +#define IRIDE ((w83877f_regs[0x16] >> 1) & 1) +#define PNPCVS ((w83877f_regs[0x16] >> 2) & 1) +#define GMDRQ ((w83877f_regs[0x16] >> 3) & 1) +#define GOIQSEL ((w83877f_regs[0x16] >> 4) & 1) + +#define DSUBLGRQ (w83877f_regs[0x17] & 1) +#define DSUALGRQ ((w83877f_regs[0x17] >> 1) & 1) +#define DSPRLGRQ ((w83877f_regs[0x17] >> 2) & 1) +#define DSFDLGRQ ((w83877f_regs[0x17] >> 3) & 1) +#define PRIRQOD ((w83877f_regs[0x17] >> 4) & 1) + +#define GMAS (w83877f_regs[0x1E] & 3) +#define GMAD (w83877f_regs[0x1E] & 0xFC) + +#define FDCAD ((w83877f_regs[0x20] & 0xFC) << 2) + +/* Main IDE base address. */ +#define IDE0AD ((w83877f_regs[0x21] & 0xFC) << 2) +/* IDE Alternate status base address. */ +#define IDE1AD ((w83877f_regs[0x22] & 0xFC) << 2) + +#define PRTAD (((uint16_t) w83877f_regs[0x23]) << 2) + +#define URAAD (((uint16_t) w83877f_regs[0x24] & 0xFE) << 2) +#define URBAD (((uint16_t) w83877f_regs[0x25] & 0xFE) << 2) + +#define PRTDQS (w83877f[regs[0x26] & 0xF) +#define FDCDQS (w83877f[regs[0x26] >> 4) + +#define PRTIQS (w83877f[regs[0x27] & 0xF) +#define ECPIRQx (w83877f[regs[0x27] >> 5) + +#define URBIQS (w83877f[regs[0x28] & 0xF) +#define URAIQS (w83877f[regs[0x28] >> 4) + +#define IQNIQS (w83877f[regs[0x29] & 0xF) +#define FDCIQS (w83877f[regs[0x29] >> 4) + +#define W83757 (!PRTMODS2 && !PRTMODS1 && !PRTMODS0) +#define EXTFDC (!PRTMODS2 && !PRTMODS1 && PRTMODS0) +#define EXTADP (!PRTMODS2 && PRTMODS1 && !PRTMODS0) +#define EXT2FDD (!PRTMODS2 && PRTMODS1 && PRTMODS0) +#define JOYSTICK (PRTMODS2 && !PRTMODS1 && !PRTMODS0) +#define EPP_SPP (PRTMODS2 && !PRTMODS1 && PRTMODS0) +#define ECP (PRTMODS2 && PRTMODS1 && !PRTMODS0) +#define ECP_EPP (PRTMODS2 && PRTMODS1 && PRTMODS0) + +static uint16_t fdc_valid_ports[2] = {0x3F0, 0x370}; +static uint16_t ide_valid_ports[2] = {0x1F0, 0x170}; +static uint16_t ide_as_valid_ports[2] = {0x3F6, 0x376}; +static uint16_t lpt1_valid_ports[3] = {0x3BC, 0x378, 0x278}; +static uint16_t com1_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; +static uint16_t com2_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; + +static void w83877f_remap() +{ + io_removehandler(0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); + io_removehandler(0x3f0, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); + io_sethandler(HEFRAS ? 0x3f0 : 0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); + winbond_port = (HEFRAS ? 0x3f0 : 0x250); + winbond_key_times = HEFRAS + 1; + winbond_key = (HEFRAS ? 0x86 : 0x88) | HEFERE; + // pclog("W83877F mapped to %04X, with key %02X required %i times\n", winbond_port, winbond_key, winbond_key_times); +} + +static uint8_t is_in_array(uint16_t *port_array, uint8_t max, uint16_t port) +{ + uint8_t i = 0; + + for (i = 0; i < max; i++) + { + if (port_array[i] == port) return 1; + } + return 0; +} + +static uint16_t make_port(uint8_t reg) +{ + uint16_t p = 0; + + switch(reg) + { + case 0x20: + p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x3F0; + if (!(is_in_array(fdc_valid_ports, 2, p))) p = 0x3F0; + w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); + break; + case 0x21: + p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x1F0; + if (!(is_in_array(ide_valid_ports, 2, p))) p = 0x1F0; + w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); + break; + case 0x22: + p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x106) || (p > 0x3F6)) p = 0x3F6; + if (!(is_in_array(ide_as_valid_ports, 2, p))) p = 0x3F6; + w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); + break; + case 0x23: + p = ((uint16_t) (w83877f_regs[reg] & 0xff)) << 2; + p &= 0xFFC; + if ((p < 0x100) || (p > 0x3F8)) p = 0x378; + if (!(is_in_array(lpt1_valid_ports, 3, p))) p = 0x378; + w83877f_regs[reg] = (p >> 2); + break; + case 0x24: + p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x3F8; + if (!(is_in_array(com1_valid_ports, 9, p))) p = 0x3F8; + w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); + break; + case 0x25: + p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x2F8; + if (!(is_in_array(com2_valid_ports, 9, p))) p = 0x2F8; + w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); + break; + } + + // pclog("Made port %04X (reg %02X)\n", p, reg); + return p; +} + +void w83877f_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint8_t max = 0x2A; + int temp; + + if (index) + { + // pclog("w83877f_write : port=%04x = %02X locked=%i\n", port, val, w83877f_locked); + + if ((val == winbond_key) && !w83877f_locked) + { + if (winbond_key_times == 2) + { + if (tries) + { + // pclog("W83877F Locked (2 tries)\n"); + w83877f_locked = 1; + // fdc_3f1_enable(0); + tries = 0; + } + else + { + tries++; + } + } + else + { + // pclog("W83877F Locked (1 try)\n"); + w83877f_locked = 1; + // fdc_3f1_enable(0); + tries = 0; + } + } + else + { + // pclog("w83877f_write : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, val, w83877f_locked); + + if (w83877f_locked) + { + if (val < max) w83877f_curreg = val; + if (val == 0xaa) + { + w83877f_locked = 0; + // fdc_3f1_enable(1); + } + } + else + { + if (tries) + tries = 0; + } + } + } + else + { + // pclog("w83877f_write : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, val, w83877f_locked); + + if (w83877f_locked) + { + if (w83877f_rw_locked) return; + if ((w83877f_curreg >= 0x26) && (w83877f_curreg <= 0x27)) return; + if (w83877f_curreg == 0x29) return; + if (w83877f_curreg == 6) val &= 0xF3; + valxor = val ^ w83877f_regs[w83877f_curreg]; + w83877f_regs[w83877f_curreg] = val; + goto process_value; + } + } + return; + +process_value: + switch(w83877f_curreg) + { + case 4: + if (valxor & 0x10) + { + serial2_remove(); + if (!(w83877f_regs[2] & 0x10)) serial2_set(make_port(0x25), w83877f_regs[0x28] & 0xF); + } + if (valxor & 0x20) + { + serial1_remove(); + if (!(w83877f_regs[4] & 0x20)) + { + serial1_set(make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); + // mouse_serial_init(); + } + } + if (valxor & 0x80) + { + lpt1_remove(); + if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); + } + break; + case 6: + if (valxor & 0x08) + { + fdc_remove(); + if (!(w83877f_regs[6] & 0x08)) fdc_add(); + } + break; + case 7: + // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); + if (valxor & 3) fdc_update_rwc(0, FDDA_TYPE ? 1 : 0); + if (valxor & 0xC) fdc_update_rwc(1, FDDB_TYPE ? 1 : 0); + break; + case 8: + // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); + if (valxor & 3) fdc_update_boot_drive(FD_BOOT); + if (valxor & 0x10) swwp = SWWP ? 1 : 0; + if (valxor & 0x20) disable_write = DISFDDWR ? 1 : 0; + break; + case 9: + // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); + if (valxor & 0x20) + { + fdc_update_enh_mode(EN3MODE ? 1 : 0); + } + if (valxor & 0x40) + { + w83877f_rw_locked = (val & 0x40) ? 1 : 0; + } + break; + case 0xB: + // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); + if (valxor & 1) fdc_update_drv2en(DRV2EN_NEG ? 0 : 1); + if (valxor & 2) fdc_update_densel_polarity(INVERTZ ? 1 : 0); + break; + case 0xC: + if (valxor & 0x20) w83877f_remap(); + break; + case 0x16: + if (valxor & 1) w83877f_remap(); + break; + case 0x23: + if (valxor) + { + lpt1_remove(); + if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); + } + break; + case 0x24: + if (valxor & 0xfe) + { + if (!(w83877f_regs[4] & 0x20)) + { + serial1_set(make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); + // mouse_serial_init(); + } + } + break; + case 0x25: + if (valxor & 0xfe) + { + if (!(w83877f_regs[2] & 0x10)) serial2_set(make_port(0x25), w83877f_regs[0x28] & 0xF); + } + break; + case 0x28: + if (valxor & 0xf) + { + if ((w83877f_regs[0x28] & 0xf) == 0) w83877f_regs[0x28] |= 0x3; + if (!(w83877f_regs[2] & 0x10)) serial2_set(make_port(0x25), w83877f_regs[0x28] & 0xF); + } + if (valxor & 0xf0) + { + if ((w83877f_regs[0x28] & 0xf0) == 0) w83877f_regs[0x28] |= 0x40; + if (!(w83877f_regs[4] & 0x20)) + { + serial1_set(make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); + // mouse_serial_init(); + } + } + break; + } +} + +uint8_t w83877f_read(uint16_t port, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + + if (!w83877f_locked) + { + // pclog("w83877f_read : port=%04x = FF locked=%i\n", port, w83877f_locked); + return 0xff; + } + + if (index) + { + // pclog("w83877f_read : port=%04x = %02X locked=%i\n", port, w83877f_curreg, w83877f_locked); + return w83877f_curreg; + } + else + { + if ((w83877f_curreg < 0x18) && w83877f_rw_locked) return 0xff; + if (w83877f_curreg == 7) + { + // pclog("w83877f_read : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, (fdc_get_rwc(0) | (fdc_get_rwc(1) << 2)), w83877f_locked); + return (fdc_get_rwc(0) | (fdc_get_rwc(1) << 2)); + } + // pclog("w83877f_read : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, w83877f_regs[w83877f_curreg], w83877f_locked); + return w83877f_regs[w83877f_curreg]; + } +} + +void w83877f_init() +{ + fdc_remove(); + fdc_add_for_superio(); + lpt1_remove(); + lpt1_init(0x378); + lpt2_remove(); + w83877f_regs[3] = 0x30; + w83877f_regs[7] = 0xF5; + w83877f_regs[9] = 0x0A; + w83877f_regs[0xA] = 0x1F; + w83877f_regs[0xC] = 0x28; + w83877f_regs[0xD] = 0xA3; + w83877f_regs[0x16] = 5; + w83877f_regs[0x1E] = 0x81; + w83877f_regs[0x20] = (0x3f0 >> 2) & 0xfc; + w83877f_regs[0x21] = (0x1f0 >> 2) & 0xfc; + w83877f_regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; + w83877f_regs[0x23] = (0x378 >> 2); + w83877f_regs[0x24] = (0x3f8 >> 2) & 0xfe; + w83877f_regs[0x25] = (0x2f8 >> 2) & 0xfe; + w83877f_regs[0x26] = (2 << 4) | 4; + w83877f_regs[0x27] = (6 << 4) | 7; + w83877f_regs[0x28] = (4 << 4) | 3; + w83877f_regs[0x29] = 0x62; + + fdc_update_densel_polarity(1); + fdc_update_densel_force(0); + fdc_update_rwc(0, 1); + fdc_update_rwc(1, 1); + fdc_update_drvrate(0, 0); + fdc_update_drvrate(1, 0); + fdc_update_enh_mode(0); + swwp = 0; + disable_write = 0; + fdc_update_drv2en(1); + fdd_swap = 0; + serial1_set(0x3f8, 4); + serial2_set(0x2f8, 3); + w83877f_remap(); + w83877f_locked = 0; + w83877f_rw_locked = 0; +} diff --git a/src/w83877f.h b/src/w83877f.h new file mode 100644 index 000000000..37595ab66 --- /dev/null +++ b/src/w83877f.h @@ -0,0 +1 @@ +extern void w83877f_init(); diff --git a/src/wd76c10.c b/src/wd76c10.c new file mode 100644 index 000000000..4f33b07d9 --- /dev/null +++ b/src/wd76c10.c @@ -0,0 +1,99 @@ +#include "ibm.h" +#include "fdc.h" +#include "io.h" +#include "mem.h" +#include "serial.h" +#include "wd76c10.h" + +static uint16_t wd76c10_0092; +static uint16_t wd76c10_2072; +static uint16_t wd76c10_2872; +static uint16_t wd76c10_5872; + +uint16_t wd76c10_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x0092: + return wd76c10_0092; + + case 0x2072: + return wd76c10_2072; + + case 0x2872: + return wd76c10_2872; + + case 0x5872: + return wd76c10_5872; + } + return 0; +} + +void wd76c10_write(uint16_t port, uint16_t val, void *priv) +{ + pclog("WD76C10 write %04X %04X\n", port, val); + switch (port) + { + case 0x0092: + wd76c10_0092 = val; + + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + + case 0x2072: + wd76c10_2072 = val; + + switch ((val >> 5) & 7) + { + case 1: serial1_set(0x3f8, 4); break; + case 2: serial1_set(0x2f8, 4); break; + case 3: serial1_set(0x3e8, 4); break; + case 4: serial1_set(0x2e8, 4); break; + } + switch ((val >> 1) & 7) + { + case 1: serial2_set(0x3f8, 3); break; + case 2: serial2_set(0x2f8, 3); break; + case 3: serial2_set(0x3e8, 3); break; + case 4: serial2_set(0x2e8, 3); break; + } + break; + + case 0x2872: + wd76c10_2872 = val; + + fdc_remove(); + if (!(val & 1)) + fdc_add(); + break; + + case 0x5872: + wd76c10_5872 = val; + break; + } +} + +uint8_t wd76c10_readb(uint16_t port, void *priv) +{ + if (port & 1) + return wd76c10_read(port & ~1, priv) >> 8; + return wd76c10_read(port, priv) & 0xff; +} + +void wd76c10_writeb(uint16_t port, uint8_t val, void *priv) +{ + uint16_t temp = wd76c10_read(port, priv); + if (port & 1) + wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv); + else + wd76c10_write(port , (temp & 0xff00) | val, priv); +} + +void wd76c10_init() +{ + io_sethandler(0x0092, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL, NULL); + io_sethandler(0x2072, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL, NULL); + io_sethandler(0x2872, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL, NULL); + io_sethandler(0x5872, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL, NULL); +} diff --git a/src/wd76c10.h b/src/wd76c10.h new file mode 100644 index 000000000..44528f0f5 --- /dev/null +++ b/src/wd76c10.h @@ -0,0 +1 @@ +void wd76c10_init(); diff --git a/src/win-config.c b/src/win-config.c new file mode 100644 index 000000000..4291802b2 --- /dev/null +++ b/src/win-config.c @@ -0,0 +1,694 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include + +#include "nethandler.h" +#include "ibm.h" +#include "ide.h" +#include "cpu.h" +#include "device.h" +#include "fdd.h" +#include "gameport.h" +#include "model.h" +#include "nvr.h" +#include "resources.h" +#include "sound.h" +#include "video.h" +#include "vid_voodoo.h" +#include "win.h" + +extern int is486; +static int romstolist[ROM_MAX], listtomodel[ROM_MAX], romstomodel[ROM_MAX], modeltolist[ROM_MAX]; +static int settings_sound_to_list[20], settings_list_to_sound[20]; +static int settings_network_to_list[20], settings_list_to_network[20]; + +static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char temp_str[256]; + HWND h; + int c, d; + int rom, gfx, mem, fpu; + int temp_cpu, temp_cpu_m, temp_model; + int temp_GAMEBLASTER, temp_GUS, temp_SSI2001, temp_voodoo, temp_sound_card_current; + int temp_dynarec; + int cpu_flags; + int temp_fda_type, temp_fdb_type; + int temp_network_card_current; + int temp_network_interface_current; + int temp_always_serial; + int temp_joystick_type; + + UDACCEL accel; +// pclog("Dialog msg %i %08X\n",message,message); + switch (message) + { + case WM_INITDIALOG: + pause = 1; + h = GetDlgItem(hdlg, IDC_COMBO1); + for (c = 0; c < ROM_MAX; c++) + romstolist[c] = 0; + c = d = 0; + while (models[c].id != -1) + { + pclog("INITDIALOG : %i %i %i\n",c,models[c].id,romspresent[models[c].id]); + if (romspresent[models[c].id]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[c].name); + modeltolist[c] = d; + listtomodel[d] = c; + romstolist[models[c].id] = d; + romstomodel[models[c].id] = c; + d++; + } + c++; + } + SendMessage(h, CB_SETCURSEL, modeltolist[model], 0); + + h = GetDlgItem(hdlg, IDC_COMBOVID); + c = d = 0; + while (1) + { + char *s = video_card_getname(c); + + if (!s[0]) + break; + + if (video_card_available(c) && gfx_present[video_new_to_old(c)]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + if (video_new_to_old(c) == gfxcard) + SendMessage(h, CB_SETCURSEL, d, 0); + + d++; + } + + c++; + } + if (models[model].fixed_gfxcard) + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + c = 0; + while (models[romstomodel[romset]].cpu[c].cpus != NULL && c < 3) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[romstomodel[romset]].cpu[c].name); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, cpu_manufacturer, 0); + if (c == 1) EnableWindow(h, FALSE); + else EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO3); + c = 0; + while (models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].cpu_type != -1) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].name); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, cpu, 0); + + h = GetDlgItem(hdlg, IDC_COMBOSND); + c = d = 0; + while (1) + { + char *s = sound_card_getname(c); + + if (!s[0]) + break; + + settings_sound_to_list[c] = d; + + if (sound_card_available(c)) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + settings_list_to_sound[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_sound_to_list[sound_card_current], 0); + + /*NIC config*/ + h = GetDlgItem(hdlg, IDC_COMBONET); + c = d = 0; + while (1) + { + char *s = network_card_getname(c); + + if (!s[0]) + break; + + settings_network_to_list[c] = d; + + if (network_card_available(c)) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + settings_list_to_network[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_network_to_list[network_card_current], 0); + + h=GetDlgItem(hdlg, IDC_CHECK3); + SendMessage(h, BM_SETCHECK, GAMEBLASTER, 0); + + h=GetDlgItem(hdlg, IDC_CHECKGUS); + SendMessage(h, BM_SETCHECK, GUS, 0); + + h=GetDlgItem(hdlg, IDC_CHECKSSI); + SendMessage(h, BM_SETCHECK, SSI2001, 0); + + h=GetDlgItem(hdlg, IDC_CHECK2); + SendMessage(h, BM_SETCHECK, slowega, 0); + + h=GetDlgItem(hdlg, IDC_CHECK4); + SendMessage(h, BM_SETCHECK, cga_comp, 0); + + h=GetDlgItem(hdlg, IDC_CHECKCBURST); + SendMessage(h, BM_SETCHECK, cga_color_burst, 0); + + h=GetDlgItem(hdlg, IDC_CHECKBROWN); + SendMessage(h, BM_SETCHECK, cga_brown, 0); + + h=GetDlgItem(hdlg, IDC_CHECKFORCE43); + SendMessage(h, BM_SETCHECK, force_43, 0); + + h=GetDlgItem(hdlg, IDC_CHECKOVERSCAN); + SendMessage(h, BM_SETCHECK, enable_overscan, 0); + + h=GetDlgItem(hdlg, IDC_CHECKFLASH); + SendMessage(h, BM_SETCHECK, enable_flash, 0); + + h=GetDlgItem(hdlg, IDC_CHECKSYNC); + SendMessage(h, BM_SETCHECK, enable_sync, 0); + + h=GetDlgItem(hdlg, IDC_CHECKSERIAL); + SendMessage(h, BM_SETCHECK, mouse_always_serial, 0); + + h=GetDlgItem(hdlg, IDC_CHECKVOODOO); + SendMessage(h, BM_SETCHECK, voodoo_enabled, 0); + + cpu_flags = models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].cpu_flags; + h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + EnableWindow(h, FALSE); + else + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && cpu_use_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + + h = GetDlgItem(hdlg, IDC_COMBOCHC); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"A little"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"A bit"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Some"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"A lot"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Infinite"); + SendMessage(h, CB_SETCURSEL, cache, 0); + + h = GetDlgItem(hdlg, IDC_COMBOSPD); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"8-bit"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Slow 16-bit"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Fast 16-bit"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Slow VLB/PCI"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Mid VLB/PCI"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Fast VLB/PCI"); + SendMessage(h, CB_SETCURSEL, video_speed, 0); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETBUDDY, (WPARAM)GetDlgItem(hdlg, IDC_MEMTEXT), 0); + SendMessage(h, UDM_SETRANGE, 0, (models[romstomodel[romset]].min_ram << 16) | models[romstomodel[romset]].max_ram); + if (!models[model].is_at) + SendMessage(h, UDM_SETPOS, 0, mem_size); + else + SendMessage(h, UDM_SETPOS, 0, mem_size / 1024); + accel.nSec = 0; + accel.nInc = models[model].ram_granularity; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + + h = GetDlgItem(hdlg, IDC_CONFIGUREVID); + if (video_card_has_config(video_old_to_new(gfxcard))) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURESND); + if (sound_card_has_config(sound_card_current)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURENET); + if (network_card_has_config(network_card_current)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBODRA); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M"); + SendMessage(h, CB_SETCURSEL, fdd_get_type(0), 0); + h = GetDlgItem(hdlg, IDC_COMBODRB); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M"); + SendMessage(h, CB_SETCURSEL, fdd_get_type(1), 0); + + h = GetDlgItem(hdlg, IDC_TEXT_MB); + if (models[model].is_at) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"MB"); + else + SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"KB"); + + h = GetDlgItem(hdlg, IDC_COMBOJOY); + c = 0; + while (joystick_get_name(c)) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)joystick_get_name(c)); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, joystick_type, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 4) ? TRUE : FALSE); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + h = GetDlgItem(hdlg, IDC_COMBO1); + temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)temp_str); + sscanf(temp_str, "%i", &mem); + mem &= ~(models[temp_model].ram_granularity - 1); + if (mem < models[temp_model].min_ram) + mem = models[temp_model].min_ram; + else if (mem > models[temp_model].max_ram) + mem = models[temp_model].max_ram; + if (models[temp_model].is_at) + mem *= 1024; + + h = GetDlgItem(hdlg, IDC_COMBOVID); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM)temp_str); + gfx = video_new_to_old(video_card_getid(temp_str)); + + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + fpu = (models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type >= CPU_i486DX) ? 1 : 0; + + h = GetDlgItem(hdlg, IDC_CHECK3); + temp_GAMEBLASTER = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKGUS); + temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKSSI); + temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKFORCE43); + force_43 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKOVERSCAN); + enable_overscan = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKCBURST); + cga_color_burst=SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKBROWN); + cga_brown=SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKFLASH); + enable_flash=SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKSYNC); + enable_sync = SendMessage(h, BM_GETCHECK, 0, 0); + update_sync(); + + h = GetDlgItem(hdlg, IDC_CHECKSERIAL); + temp_always_serial = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKVOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBOSND); + temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBONET); + temp_network_card_current = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBODRA); + temp_fda_type = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBODRB); + temp_fdb_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (temp_model != model || gfx != gfxcard || mem != mem_size || temp_cpu != cpu || temp_cpu_m != cpu_manufacturer || + fpu != hasfpu || temp_GAMEBLASTER != GAMEBLASTER || temp_GUS != GUS || + temp_SSI2001 != SSI2001 || temp_sound_card_current != sound_card_current || + temp_voodoo != voodoo_enabled || temp_dynarec != cpu_use_dynarec || temp_always_serial != mouse_always_serial || + temp_fda_type != fdd_get_type(0) || temp_fdb_type != fdd_get_type(1) || temp_network_card_current != network_card_current) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL)==IDOK) + { + savenvr(); + model = temp_model; + romset = model_getromset(); + gfxcard = gfx; + mem_size = mem; + cpu_manufacturer = temp_cpu_m; + cpu = temp_cpu; + GAMEBLASTER = temp_GAMEBLASTER; + GUS = temp_GUS; + SSI2001 = temp_SSI2001; + sound_card_current = temp_sound_card_current; + voodoo_enabled = temp_voodoo; + cpu_use_dynarec = temp_dynarec; + + fdd_set_type(0, temp_fda_type); + fdd_set_type(1, temp_fdb_type); + + network_card_current = temp_network_card_current; + mouse_always_serial = temp_always_serial; + + mem_resize(); + loadbios(); + resetpchard(); + } + else + { + EndDialog(hdlg, 0); + pause = 0; + return TRUE; + } + } + + h = GetDlgItem(hdlg, IDC_COMBOSPD); + video_speed = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK4); + cga_comp=SendMessage(h, BM_GETCHECK, 0, 0); + + cpu_manufacturer = temp_cpu_m; + cpu = temp_cpu; + cpu_set(); + + h = GetDlgItem(hdlg, IDC_COMBOCHC); + cache=SendMessage(h, CB_GETCURSEL, 0, 0); + mem_updatecache(); + + saveconfig(); + + speedchanged(); + + joystick_type = temp_joystick_type; + gameport_update_joystick_type(); + + case IDCANCEL: + EndDialog(hdlg, 0); + pause=0; + return TRUE; + case IDC_COMBO1: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg,IDC_COMBO1); + temp_model = listtomodel[SendMessage(h,CB_GETCURSEL,0,0)]; + + /*Enable/disable gfxcard list*/ + h = GetDlgItem(hdlg, IDC_COMBOVID); + if (!models[temp_model].fixed_gfxcard) + { + char *s = video_card_getname(video_old_to_new(gfxcard)); + + EnableWindow(h, TRUE); + + c = 0; + while (1) + { + SendMessage(h, CB_GETLBTEXT, c, (LPARAM)temp_str); + if (!strcmp(temp_str, s)) + break; + c++; + } + SendMessage(h, CB_SETCURSEL, c, 0); + } + else + EnableWindow(h, FALSE); + + /*Rebuild manufacturer list*/ + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[c].cpus != NULL && c < 3) + { + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[c].name); + c++; + } + if (temp_cpu_m >= c) temp_cpu_m = c - 1; + SendMessage(h, CB_SETCURSEL, temp_cpu_m, 0); + if (c == 1) EnableWindow(h, FALSE); + else EnableWindow(h, TRUE); + + /*Rebuild CPU list*/ + h = GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[temp_cpu_m].cpus[c].name); + c++; + } + if (temp_cpu >= c) temp_cpu = c - 1; + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + + h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + cpu_flags = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + EnableWindow(h, FALSE); + else + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + + h = GetDlgItem(hdlg, IDC_TEXT_MB); + if (models[temp_model].is_at) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"MB"); + else + SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"KB"); + + h = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)temp_str); + sscanf(temp_str, "%i", &mem); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETRANGE, 0, (models[temp_model].min_ram << 16) | models[temp_model].max_ram); + mem &= ~(models[temp_model].ram_granularity - 1); + if (mem < models[temp_model].min_ram) + mem = models[temp_model].min_ram; + else if (mem > models[temp_model].max_ram) + mem = models[temp_model].max_ram; + SendMessage(h, UDM_SETPOS, 0, mem); + accel.nSec = 0; + accel.nInc = models[temp_model].ram_granularity; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + } + break; + case IDC_COMBOCPUM: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO1); + temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + + /*Rebuild CPU list*/ + h=GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[temp_cpu_m].cpus[c].name); + c++; + } + if (temp_cpu >= c) temp_cpu = c - 1; + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + + h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + cpu_flags = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + EnableWindow(h, FALSE); + else + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + } + break; + case IDC_COMBO3: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO1); + temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + h=GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + cpu_flags = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + EnableWindow(h, FALSE); + else + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + } + break; + + case IDC_CONFIGUREVID: + h = GetDlgItem(hdlg, IDC_COMBOVID); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM)temp_str); + + deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(temp_str))); + break; + + case IDC_COMBOVID: + h = GetDlgItem(hdlg, IDC_COMBOVID); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM)temp_str); + gfx = video_card_getid(temp_str); + + h = GetDlgItem(hdlg, IDC_CONFIGUREVID); + if (video_card_has_config(gfx)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGURESND: + h = GetDlgItem(hdlg, IDC_COMBOSND); + temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card_current)); + break; + + case IDC_COMBOSND: + h = GetDlgItem(hdlg, IDC_COMBOSND); + temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURESND); + if (sound_card_has_config(temp_sound_card_current)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGURENET: + h = GetDlgItem(hdlg, IDC_COMBONET); + temp_network_card_current = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_network_card_current)); + break; + + case IDC_COMBONET: + h = GetDlgItem(hdlg, IDC_COMBONET); + temp_network_card_current = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURENET); + if (network_card_has_config(temp_network_card_current)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGUREVOODOO: + deviceconfig_open(hdlg, (void *)&voodoo_device); + break; + + case IDC_COMBOJOY: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 4) ? TRUE : FALSE); + } + break; + + case IDC_JOY1: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 0, temp_joystick_type); + break; + case IDC_JOY2: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 1, temp_joystick_type); + break; + case IDC_JOY3: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 2, temp_joystick_type); + break; + case IDC_JOY4: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 3, temp_joystick_type); + break; + } + break; + } + return FALSE; +} + +void config_open(HWND hwnd) +{ + DialogBox(hinstance, TEXT("ConfigureDlg"), hwnd, config_dlgproc); +} diff --git a/src/win-d3d-fs.cc b/src/win-d3d-fs.cc new file mode 100644 index 000000000..7603dd23f --- /dev/null +++ b/src/win-d3d-fs.cc @@ -0,0 +1,506 @@ +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include +#include "resources.h" +#include "video.h" +#include "win-d3d-fs.h" +#include "win.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +static void d3d_fs_init_objects(); +static void d3d_fs_close_objects(); +static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECT3D9 d3d = NULL; +static LPDIRECT3DDEVICE9 d3ddev = NULL; +static LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +static LPDIRECT3DTEXTURE9 d3dTexture = NULL; +static D3DPRESENT_PARAMETERS d3dpp; + +static HWND d3d_hwnd; +static HWND d3d_device_window; + +static int d3d_fs_w, d3d_fs_h; + +struct CUSTOMVERTEX +{ + FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + FLOAT tu, tv; +}; + +static PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +static CUSTOMVERTEX d3d_verts[] = +{ + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, + { 0.0f, 2080.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2080.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f}, + {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, +}; + +void d3d_fs_init(HWND h) +{ + int c; + HRESULT hr; + + d3d_fs_w = GetSystemMetrics(SM_CXSCREEN); + d3d_fs_h = GetSystemMetrics(SM_CYSCREEN); + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + d3d_hwnd = h; + + d3d_device_window = CreateWindowEx ( + 0, + szSubClassName, + "PCem v11 [Experimental]", + WS_POPUP, + CW_USEDEFAULT, + CW_USEDEFAULT, + 640, + 480, + HWND_DESKTOP, + NULL, + NULL, + NULL + ); + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_device_window; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = false; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferWidth = d3d_fs_w; + d3dpp.BackBufferHeight = d3d_fs_h; + + hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); + + d3d_fs_init_objects(); + + video_blit_memtoscreen = d3d_fs_blit_memtoscreen; + video_blit_memtoscreen_8 = d3d_fs_blit_memtoscreen_8; +} + +static void d3d_fs_close_objects() +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } +} + +static void d3d_fs_init_objects() +{ + HRESULT hr; + D3DLOCKED_RECT dr; + int y; + RECT r; + + hr = d3ddev->CreateVertexBuffer(6*sizeof(CUSTOMVERTEX), + 0, + D3DFVF_XYZRHW | D3DFVF_TEX1, + D3DPOOL_MANAGED, + &v_buffer, + NULL); + + d3ddev->CreateTexture(2080, 2080, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); + + r.top = r.left = 0; + r.bottom = 2079; + r.right = 2079; + + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (y = 0; y < 2080; y++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (y * dr.Pitch)); + memset(p, 0, 2080 * 4); + } + + d3dTexture->UnlockRect(0); + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); +} + +/*void d3d_resize(int x, int y) +{ + HRESULT hr; + + d3dpp.BackBufferWidth = x; + d3dpp.BackBufferHeight = y; + + d3d_reset(); +}*/ + +void d3d_fs_reset() +{ + HRESULT hr; + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_device_window; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = false; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferWidth = d3d_fs_w; + d3dpp.BackBufferHeight = d3d_fs_h; + + hr = d3ddev->Reset(&d3dpp); + + if (hr == D3DERR_DEVICELOST) + return; + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + device_force_redraw(); +} + +void d3d_fs_close() +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } + if (d3ddev) + { + d3ddev->Release(); + d3ddev = NULL; + } + if (d3d) + { + d3d->Release(); + d3d = NULL; + } + DestroyWindow(d3d_device_window); +} + +static void d3d_fs_size(RECT window_rect, double *l, double *t, double *r, double *b, int w, int h) +{ + int ratio_w, ratio_h; + switch (video_fullscreen_scale) + { + case FULLSCR_SCALE_FULL: + *l = -0.5; + *t = -0.5; + *r = (window_rect.right - window_rect.left) - 0.5; + *b = (window_rect.bottom - window_rect.top) - 0.5; + break; + case FULLSCR_SCALE_43: + *t = -0.5; + *b = (window_rect.bottom - window_rect.top) - 0.5; + *l = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)) - 0.5; + *r = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)) - 0.5; + if (*l < -0.5) + { + *l = -0.5; + *r = (window_rect.right - window_rect.left) - 0.5; + *t = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * 3) / (4 * 2)) - 0.5; + *b = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * 3) / (4 * 2)) - 0.5; + } + break; + case FULLSCR_SCALE_SQ: + *t = -0.5; + *b = (window_rect.bottom - window_rect.top) - 0.5; + *l = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * w) / (h * 2)) - 0.5; + *r = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * w) / (h * 2)) - 0.5; + if (*l < -0.5) + { + *l = -0.5; + *r = (window_rect.right - window_rect.left) - 0.5; + *t = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * h) / (w * 2)) - 0.5; + *b = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * h) / (w * 2)) - 0.5; + } + break; + case FULLSCR_SCALE_INT: + ratio_w = (window_rect.right - window_rect.left) / w; + ratio_h = (window_rect.bottom - window_rect.top) / h; + if (ratio_h < ratio_w) + ratio_w = ratio_h; + *l = ((window_rect.right - window_rect.left) / 2) - ((w * ratio_w) / 2) - 0.5; + *r = ((window_rect.right - window_rect.left) / 2) + ((w * ratio_w) / 2) - 0.5; + *t = ((window_rect.bottom - window_rect.top) / 2) - ((h * ratio_w) / 2) - 0.5; + *b = ((window_rect.bottom - window_rect.top) / 2) + ((h * ratio_w) / 2) - 0.5; + break; + } +} + +static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + HRESULT hr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT window_rect; + uint32_t *p, *src; + int yy; + double l, t, r, b; + + if (y1 == y2) + return; /*Nothing to do*/ + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + + GetClientRect(d3d_device_window, &window_rect); + d3d_fs_size(window_rect, &l, &t, &r, &b, w, h); + + d3d_verts[0].x = l; + d3d_verts[0].y = t; + d3d_verts[1].x = r; + d3d_verts[1].y = b; + d3d_verts[2].x = l; + d3d_verts[2].y = b; + d3d_verts[3].x = l; + d3d_verts[3].y = t; + d3d_verts[4].x = r; + d3d_verts[4].y = t; + d3d_verts[5].x = r; + d3d_verts[5].y = b; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); + if (hr == D3D_OK) + hr = v_buffer->Unlock(); + + if (hr == D3D_OK && !(y1 == 0 && y2 == 0)) + { + RECT lock_rect; + + lock_rect.top = y1; + lock_rect.left = 0; + lock_rect.bottom = y2; + lock_rect.right = 2079; + + if (FAILED(d3dTexture->LockRect(0, &dr, &lock_rect, 0))) + fatal("LockRect failed\n"); + + for (yy = y1; yy < y2; yy++) + memcpy(dr.pBits + ((yy - y1) * dr.Pitch), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + + d3dTexture->UnlockRect(0); + } + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0, 0); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_device_window, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(ghwnd, WM_RESETD3D, 0, 0); +} + +static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h) +{ + HRESULT hr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT window_rect; + uint32_t *p, *src; + int xx, yy; + double l, t, r, b; + + if (!h) + return; /*Nothing to do*/ + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + + GetClientRect(d3d_device_window, &window_rect); + d3d_fs_size(window_rect, &l, &t, &r, &b, w, h); + + d3d_verts[0].x = l; + d3d_verts[0].y = t; + d3d_verts[1].x = r; + d3d_verts[1].y = b; + d3d_verts[2].x = l; + d3d_verts[2].y = b; + d3d_verts[3].x = l; + d3d_verts[3].y = t; + d3d_verts[4].x = r; + d3d_verts[4].y = t; + d3d_verts[5].x = r; + d3d_verts[5].y = b; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); + if (hr == D3D_OK) + hr = v_buffer->Unlock(); + + if (hr == D3D_OK) + { + RECT lock_rect; + + lock_rect.top = 0; + lock_rect.left = 0; + lock_rect.bottom = 2079; + lock_rect.right = 2079; + + if (FAILED(d3dTexture->LockRect(0, &dr, &lock_rect, 0))) + fatal("LockRect failed\n"); + + for (yy = 0; yy < h; yy++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (yy * dr.Pitch)); + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + for (xx = 0; xx < w; xx++) + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + + d3dTexture->UnlockRect(0); + } + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0, 0); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_device_window, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(ghwnd, WM_RESETD3D, 0, 0); +} + +void d3d_fs_take_screenshot(char *fn) +{ + HRESULT hr = D3D_OK; + LPDIRECT3DSURFACE9 d3dSurface = NULL; + + if (!d3dTexture) return; + + hr = d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + hr = D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + + d3dSurface->Release(); + d3dSurface = NULL; +} diff --git a/src/win-d3d-fs.h b/src/win-d3d-fs.h new file mode 100644 index 000000000..e0684ec1c --- /dev/null +++ b/src/win-d3d-fs.h @@ -0,0 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif + void d3d_fs_init(HWND h); + void d3d_fs_close(); + void d3d_fs_reset(); + void d3d_fs_resize(int x, int y); +#ifdef __cplusplus +} +#endif diff --git a/src/win-d3d.cc b/src/win-d3d.cc new file mode 100644 index 000000000..a5a04b824 --- /dev/null +++ b/src/win-d3d.cc @@ -0,0 +1,401 @@ +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include +#include "resources.h" +#include "win-d3d.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +void d3d_init_objects(); +void d3d_close_objects(); +void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +void d3d_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECT3D9 d3d = NULL; +static LPDIRECT3DDEVICE9 d3ddev = NULL; +static LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +static LPDIRECT3DTEXTURE9 d3dTexture = NULL; +static D3DPRESENT_PARAMETERS d3dpp; + +static HWND d3d_hwnd; + +struct CUSTOMVERTEX +{ + FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + FLOAT tu, tv; +}; + +static PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +static CUSTOMVERTEX d3d_verts[] = +{ + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, + { 0.0f, 2080.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2080.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f}, + {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, +}; + +void d3d_init(HWND h) +{ + int c; + HRESULT hr; + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + d3d_hwnd = h; + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = h; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = true; + d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + + hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); + + d3d_init_objects(); + + video_blit_memtoscreen = d3d_blit_memtoscreen; + video_blit_memtoscreen_8 = d3d_blit_memtoscreen_8; +} + +void d3d_close_objects() +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } +} + +void d3d_init_objects() +{ + HRESULT hr; + D3DLOCKED_RECT dr; + int y; + RECT r; + + hr = d3ddev->CreateVertexBuffer(6*sizeof(CUSTOMVERTEX), + 0, + D3DFVF_XYZRHW | D3DFVF_TEX1, + D3DPOOL_MANAGED, + &v_buffer, + NULL); + + d3ddev->CreateTexture(2080, 2080, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); + + r.top = r.left = 0; + r.bottom = 2079; + r.right = 2079; + + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (y = 0; y < 2056; y++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (y * dr.Pitch)); + memset(p, 0, 2064 * 4); + } + + d3dTexture->UnlockRect(0); + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); +} + +void d3d_resize(int x, int y) +{ + HRESULT hr; + + d3dpp.BackBufferWidth = x; + d3dpp.BackBufferHeight = y; + + d3d_reset(); +} + +void d3d_reset() +{ + HRESULT hr; + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_hwnd; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = true; + d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + + hr = d3ddev->Reset(&d3dpp); + + if (hr == D3DERR_DEVICELOST) + return; + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + device_force_redraw(); +} + +void d3d_close() +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } + if (d3ddev) + { + d3ddev->Release(); + d3ddev = NULL; + } + if (d3d) + { + d3d->Release(); + d3d = NULL; + } +} + +void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + HRESULT hr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT r; + uint32_t *p, *src; + int yy; + + if (y1 == y2) + return; /*Nothing to do*/ + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2048.0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2048.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + + GetClientRect(d3d_hwnd, &r); + d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; + d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; + d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right - r.left) - 0.5; + d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom - r.top) - 0.5; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); // copy the vertices to the locked buffer + if (hr == D3D_OK) + hr = v_buffer->Unlock(); // unlock the vertex buffer + + r.top = y1; + r.left = 0; + r.bottom = y2; + r.right = 2079; + + if (hr == D3D_OK) + { + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (yy = y1; yy < y2; yy++) + memcpy(dr.pBits + ((yy - y1) * dr.Pitch), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + + d3dTexture->UnlockRect(0); + } + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_hwnd, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(d3d_hwnd, WM_RESETD3D, 0, 0); +} + +void d3d_blit_memtoscreen_8(int x, int y, int w, int h) +{ + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT r; + uint32_t *p, *src; + int yy, xx; + HRESULT hr = D3D_OK; + + if (h == 0) + return; /*Nothing to do*/ + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2080.0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2080.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + + GetClientRect(d3d_hwnd, &r); + d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; + d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; + d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right - r.left) - 0.5; + d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom - r.top) - 0.5; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); // copy the vertices to the locked buffer + if (hr == D3D_OK) + hr = v_buffer->Unlock(); // unlock the vertex buffer + + r.top = 0; + r.left = 0; + r.bottom = h; + r.right = 2079; + + if (hr == D3D_OK) + { + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (yy = 0; yy < h; yy++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (yy * dr.Pitch)); + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + for (xx = 0; xx < w; xx++) + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + + d3dTexture->UnlockRect(0); + } + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_hwnd, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(d3d_hwnd, WM_RESETD3D, 0, 0); +} + +void d3d_take_screenshot(char *fn) +{ + HRESULT hr = D3D_OK; + LPDIRECT3DSURFACE9 d3dSurface = NULL; + + if (!d3dTexture) return; + + hr = d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + hr = D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + + d3dSurface->Release(); + d3dSurface = NULL; +} diff --git a/src/win-d3d.h b/src/win-d3d.h new file mode 100644 index 000000000..33a23432a --- /dev/null +++ b/src/win-d3d.h @@ -0,0 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif + void d3d_init(HWND h); + void d3d_close(); + void d3d_reset(); + void d3d_resize(int x, int y); +#ifdef __cplusplus +} +#endif diff --git a/src/win-ddraw-fs.cc b/src/win-ddraw-fs.cc new file mode 100644 index 000000000..b598d0a28 --- /dev/null +++ b/src/win-ddraw-fs.cc @@ -0,0 +1,336 @@ +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "win-ddraw-fs.h" +#include "win-ddraw-screenshot.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +extern "C" void ddraw_fs_init(HWND h); +extern "C" void ddraw_fs_close(); + +static void ddraw_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECTDRAW lpdd = NULL; +static LPDIRECTDRAW4 lpdd4 = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_pri = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_back = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_back2 = NULL; +static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; +static DDSURFACEDESC2 ddsd; + +static HWND ddraw_hwnd; +static int ddraw_w, ddraw_h; + +static PALETTE cgapal = +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +void ddraw_fs_init(HWND h) +{ + int c; + + ddraw_w = GetSystemMetrics(SM_CXSCREEN); + ddraw_h = GetSystemMetrics(SM_CYSCREEN); + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) + fatal("DirectDrawCreate failed\n"); + + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) + fatal("QueryInterface failed\n"); + + lpdd->Release(); + lpdd = NULL; + + atexit(ddraw_fs_close); + + if (FAILED(lpdd4->SetCooperativeLevel(h, DDSCL_SETFOCUSWINDOW | + DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT))) + fatal("SetCooperativeLevel failed\n"); + + if (FAILED(lpdd4->SetDisplayMode(ddraw_w, ddraw_h, 32, 0 ,0))) + fatal("SetDisplayMode failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.dwBackBufferCount = 1; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) + fatal("CreateSurface failed\n"); + + ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; + if (FAILED(lpdds_pri->GetAttachedSurface(&ddsd.ddsCaps, &lpdds_back2))) + fatal("CreateSurface back failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2080; + ddsd.dwHeight = 2080; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) + fatal("CreateSurface back failed\n"); + + pclog("DDRAW_INIT complete\n"); + ddraw_hwnd = h; + video_blit_memtoscreen = ddraw_fs_blit_memtoscreen; + video_blit_memtoscreen_8 = ddraw_fs_blit_memtoscreen_8; +} + +void ddraw_fs_close() +{ + if (lpdds_back2) + { + lpdds_back2->Release(); + lpdds_back2 = NULL; + } + if (lpdds_back) + { + lpdds_back->Release(); + lpdds_back = NULL; + } + if (lpdds_pri) + { + lpdds_pri->Release(); + lpdds_pri = NULL; + } + if (lpdd_clipper) + { + lpdd_clipper->Release(); + lpdd_clipper = NULL; + } + if (lpdd4) + { + lpdd4->Release(); + lpdd4 = NULL; + } +} + +static void ddraw_fs_size(RECT window_rect, RECT *r_dest, int w, int h) +{ + int ratio_w, ratio_h; + switch (video_fullscreen_scale) + { + case FULLSCR_SCALE_FULL: + r_dest->left = 0; + r_dest->top = 0; + r_dest->right = (window_rect.right - window_rect.left) - 1; + r_dest->bottom = (window_rect.bottom - window_rect.top) - 1; + break; + case FULLSCR_SCALE_43: + r_dest->top = 0; + r_dest->bottom = (window_rect.bottom - window_rect.top) - 1; + r_dest->left = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)); + r_dest->right = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)) - 1; + if (r_dest->left < 0) + { + r_dest->left = 0; + r_dest->right = (window_rect.right - window_rect.left) - 1; + r_dest->top = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * 3) / (4 * 2)); + r_dest->bottom = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * 3) / (4 * 2)) - 1; + } + break; + case FULLSCR_SCALE_SQ: + r_dest->top = 0; + r_dest->bottom = (window_rect.bottom - window_rect.top) - 1; + r_dest->left = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * w) / (h * 2)); + r_dest->right = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * w) / (h * 2)) - 1; + if (r_dest->left < 0) + { + r_dest->left = 0; + r_dest->right = (window_rect.right - window_rect.left) - 1; + r_dest->top = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * h) / (w * 2)); + r_dest->bottom = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * h) / (w * 2)) - 1; + } + break; + case FULLSCR_SCALE_INT: + ratio_w = (window_rect.right - window_rect.left) / w; + ratio_h = (window_rect.bottom - window_rect.top) / h; + if (ratio_h < ratio_w) + ratio_w = ratio_h; + r_dest->left = ((window_rect.right - window_rect.left) / 2) - ((w * ratio_w) / 2); + r_dest->right = ((window_rect.right - window_rect.left) / 2) + ((w * ratio_w) / 2) - 1; + r_dest->top = ((window_rect.bottom - window_rect.top) / 2) - ((h * ratio_w) / 2); + r_dest->bottom = ((window_rect.bottom - window_rect.top) / 2) + ((h * ratio_w) / 2) - 1; + break; + } +} + +static void ddraw_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + RECT r_src; + RECT r_dest; + RECT window_rect; + int yy; + HRESULT hr; + DDBLTFX ddbltfx; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = y1; yy < y2; yy++) + { + if ((y + yy) >= 0) memcpy((unsigned char*)ddsd.lpSurface + (yy * ddsd.lPitch), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + lpdds_back->Unlock(NULL); + + window_rect.left = 0; + window_rect.top = 0; + window_rect.right = ddraw_w; + window_rect.bottom = ddraw_h; + ddraw_fs_size(window_rect, &r_dest, w, h); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0; + + lpdds_back2->Blt(&window_rect, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + + hr = lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash && enable_flash) + { + RECT r; + r.left = window_rect.right - 40; + r.right = window_rect.right - 8; + r.top = 8; + r.bottom = 14; + ddbltfx.dwFillColor = 0xffffff; + lpdds_back2->Blt(&r, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + } + + hr = lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); + } +} + +static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h) +{ + RECT r_src; + RECT r_dest; + RECT window_rect; + int xx, yy; + HRESULT hr; + DDBLTFX ddbltfx; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + uint32_t *p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = 0; xx < w; xx++) + { + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + /* If brown circuity is disabled, double the green component. */ + if ((buffer->line[y + yy][x + xx] == 0x16) && !cga_brown) p[xx] += (p[xx] & 0xff00); + } + } + } + lpdds_back->Unlock(NULL); + + window_rect.left = 0; + window_rect.top = 0; + window_rect.right = ddraw_w; + window_rect.bottom = ddraw_h; + ddraw_fs_size(window_rect, &r_dest, w, h); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0; + + lpdds_back2->Blt(&window_rect, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + + hr = lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash && enable_flash) + { + RECT r; + r.left = window_rect.right - 40; + r.right = window_rect.right - 8; + r.top = 8; + r.bottom = 14; + ddbltfx.dwFillColor = 0xffffff; + lpdds_back2->Blt(&r, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + } + + lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); +} + +void ddraw_fs_take_screenshot(char *fn) +{ + ddraw_common_take_screenshot(fn, lpdds_back2); +} diff --git a/src/win-ddraw-fs.h b/src/win-ddraw-fs.h new file mode 100644 index 000000000..89a863e1f --- /dev/null +++ b/src/win-ddraw-fs.h @@ -0,0 +1,8 @@ +#ifdef __cplusplus +extern "C" { +#endif + void ddraw_fs_init(HWND h); + void ddraw_fs_close(); +#ifdef __cplusplus +} +#endif diff --git a/src/win-ddraw-screenshot.cc b/src/win-ddraw-screenshot.cc new file mode 100644 index 000000000..c397ee862 --- /dev/null +++ b/src/win-ddraw-screenshot.cc @@ -0,0 +1,169 @@ +#include +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "win-ddraw-screenshot.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +extern "C" void ddraw_init(HWND h); +extern "C" void ddraw_close(); + +HBITMAP hbitmap; + +int xs, ys, ys2; + +void CopySurface(IDirectDrawSurface4 *pDDSurface) +{ + HDC hdc, hmemdc; + + HBITMAP hprevbitmap; + + DDSURFACEDESC2 ddsd2; + + pDDSurface->GetDC(&hdc); + + hmemdc = CreateCompatibleDC(hdc); + + ZeroMemory(&ddsd2 ,sizeof( ddsd2 )); // better to clear before using + + ddsd2.dwSize = sizeof( ddsd2 ); //initialize with size + + pDDSurface->GetSurfaceDesc(&ddsd2); + + hbitmap = CreateCompatibleBitmap( hdc ,xs ,ys); + + hprevbitmap = (HBITMAP) SelectObject( hmemdc, hbitmap ); + + BitBlt(hmemdc,0 ,0 ,xs ,ys ,hdc ,0 ,0,SRCCOPY); + + SelectObject(hmemdc,hprevbitmap); // restore the old bitmap + + DeleteDC(hmemdc); + + pDDSurface->ReleaseDC(hdc); + + return ; +} + +void DoubleLines(uint8_t *dst, uint8_t *src) +{ + int i = 0; + uint8_t temp_buf[8320]; + for (i = 0; i < ys; i++) + { + memcpy(dst + (i * xs * 8), src + (i * xs * 4), xs * 4); + memcpy(dst + ((i * xs * 8) + (xs * 4)), src + (i * xs * 4), xs * 4); + } +} + +void SaveBitmap(char *szFilename,HBITMAP hBitmap) +{ + HDC hdc=NULL; + FILE* fp=NULL; + LPVOID pBuf=NULL; + LPVOID pBuf2=NULL; + BITMAPINFO bmpInfo; + BITMAPFILEHEADER bmpFileHeader; + + do{ + + hdc=GetDC(NULL); + + ZeroMemory(&bmpInfo,sizeof(BITMAPINFO)); + + bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + + GetDIBits(hdc,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS); + + if(bmpInfo.bmiHeader.biSizeImage<=0) + bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; + + if((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage))==NULL) + { + // pclog("ERROR: Unable to Allocate Bitmap Memory"); + break; + } + + if (ys2 <= 250) + { + pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage * 2); + } + + bmpInfo.bmiHeader.biCompression=BI_RGB; + + GetDIBits(hdc,hBitmap,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo, DIB_RGB_COLORS); + + if((fp = fopen(szFilename,"wb"))==NULL) + { + MessageBox( NULL, "Unable to Create Bitmap File", "Error", MB_OK|MB_ICONERROR); + break; + } + + bmpFileHeader.bfReserved1=0; + + bmpFileHeader.bfReserved2=0; + + if (pBuf2) + { + bmpInfo.bmiHeader.biSizeImage <<= 1; + bmpInfo.bmiHeader.biHeight <<= 1; + } + + bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage; + + bmpFileHeader.bfType='MB'; + + bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); + + fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp); + + fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp); + + if (pBuf2) + { + DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf); + fwrite(pBuf2,bmpInfo.bmiHeader.biSizeImage,1,fp); + } + else + { + fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp); + } + + }while(false); + + if(hdc) ReleaseDC(NULL,hdc); + + if(pBuf2) free(pBuf2); + + if(pBuf) free(pBuf); + + if(fp) fclose(fp); +} + +void ddraw_common_take_screenshot(char *fn, IDirectDrawSurface4 *pDDSurface) +{ + xs = xsize; + ys = ys2 = ysize; + /* For EGA/(S)VGA, the size is NOT adjusted for overscan. */ + if ((overscan_y > 16) && enable_overscan) + { + xs += overscan_x; + ys += overscan_y; + } + /* For CGA, the width is adjusted for overscan, but the height is not. */ + if (overscan_y == 16) + { + if (ys2 <= 250) + ys += (overscan_y >> 1); + else + ys += overscan_y; + } + CopySurface(pDDSurface); + SaveBitmap(fn, hbitmap); +} diff --git a/src/win-ddraw-screenshot.h b/src/win-ddraw-screenshot.h new file mode 100644 index 000000000..c493c4fb0 --- /dev/null +++ b/src/win-ddraw-screenshot.h @@ -0,0 +1 @@ +void ddraw_common_take_screenshot(char *fn, IDirectDrawSurface4 *pDDSurface); diff --git a/src/win-ddraw.cc b/src/win-ddraw.cc new file mode 100644 index 000000000..d449f42fa --- /dev/null +++ b/src/win-ddraw.cc @@ -0,0 +1,315 @@ +#include +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "win-ddraw.h" +#include "win-ddraw-screenshot.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +extern "C" void ddraw_init(HWND h); +extern "C" void ddraw_close(); + +static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECTDRAW lpdd = NULL; +static LPDIRECTDRAW4 lpdd4 = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_pri = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_back = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_back2 = NULL; +static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; +static DDSURFACEDESC2 ddsd; + +static HWND ddraw_hwnd; + +static PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +void ddraw_init(HWND h) +{ + int c; + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) + fatal("DirectDrawCreate failed\n"); + + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) + fatal("QueryInterface failed\n"); + + lpdd->Release(); + lpdd = NULL; + + atexit(ddraw_close); + + if (FAILED(lpdd4->SetCooperativeLevel(h, DDSCL_NORMAL))) + fatal("SetCooperativeLevel failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) + fatal("CreateSurface failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2080; + ddsd.dwHeight = 2080; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) + fatal("CreateSurface back failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2080; + ddsd.dwHeight = 2080; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL))) + fatal("CreateSurface back failed\n"); + + if (FAILED(lpdd4->CreateClipper(0, &lpdd_clipper, NULL))) + fatal("CreateClipper failed\n"); + if (FAILED(lpdd_clipper->SetHWnd(0, h))) + fatal("SetHWnd failed\n"); + if (FAILED(lpdds_pri->SetClipper(lpdd_clipper))) + fatal("SetClipper failed\n"); + + pclog("DDRAW_INIT complete\n"); + ddraw_hwnd = h; + video_blit_memtoscreen = ddraw_blit_memtoscreen; + video_blit_memtoscreen_8 = ddraw_blit_memtoscreen_8; +} + +void ddraw_close() +{ + if (lpdds_back2) + { + lpdds_back2->Release(); + lpdds_back2 = NULL; + } + if (lpdds_back) + { + lpdds_back->Release(); + lpdds_back = NULL; + } + if (lpdds_pri) + { + lpdds_pri->Release(); + lpdds_pri = NULL; + } + if (lpdd_clipper) + { + lpdd_clipper->Release(); + lpdd_clipper = NULL; + } + if (lpdd4) + { + lpdd4->Release(); + lpdd4 = NULL; + } +} + +static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + RECT r_src; + RECT r_dest; + int xx, yy; + POINT po; + uint32_t *p; + HRESULT hr; + +// pclog("Blit memtoscreen %i,%i %i %i %i,%i\n", x, y, y1, y2, w, h); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = y1; yy < y2; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + memcpy(ddsd.lpSurface + (yy * ddsd.lPitch), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + lpdds_back->Unlock(NULL); + + po.x = po.y = 0; + + ClientToScreen(ddraw_hwnd, &po); + GetClientRect(ddraw_hwnd, &r_dest); + OffsetRect(&r_dest, po.x, po.y); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + hr = lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash) + { + readflash = 0; + if (enable_flash) + { + hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 8; yy < 14; yy++) + { + p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = (w - 40); xx < (w - 8); xx++) + p[xx] = 0xffffffff; + } + } + } + lpdds_back2->Unlock(NULL); + +// pclog("Blit from %i,%i %i,%i to %i,%i %i,%i\n", r_src.left, r_src.top, r_src.right, r_src.bottom, r_dest.left, r_dest.top, r_dest.right, r_dest.bottom); + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + } +} + +static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h) +{ + RECT r_src; + RECT r_dest; + int xx, yy; + POINT po; + uint32_t *p; + HRESULT hr; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = 0; xx < w; xx++) + { + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + /* If brown circuity is disabled, double the green component. */ + if ((buffer->line[y + yy][x + xx] == 0x16) && !cga_brown) p[xx] += (p[xx] & 0xff00); + } + } + } + p = (uint32_t *)(ddsd.lpSurface + (4 * ddsd.lPitch)); + lpdds_back->Unlock(NULL); + + po.x = po.y = 0; + + ClientToScreen(ddraw_hwnd, &po); + GetClientRect(ddraw_hwnd, &r_dest); + OffsetRect(&r_dest, po.x, po.y); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + hr = lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash) + { + readflash = 0; + if (enable_flash) + { + hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 8; yy < 14; yy++) + { + p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = (w - 40); xx < (w - 8); xx++) + p[xx] = 0xffffffff; + } + lpdds_back2->Unlock(NULL); + } + } + + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + } +} + +void ddraw_take_screenshot(char *fn) +{ + ddraw_common_take_screenshot(fn, lpdds_back2); +} diff --git a/src/win-ddraw.h b/src/win-ddraw.h new file mode 100644 index 000000000..3d3ecb39a --- /dev/null +++ b/src/win-ddraw.h @@ -0,0 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + void ddraw_init(HWND h); + void ddraw_close(); +#ifdef __cplusplus +} +#endif + diff --git a/src/win-deviceconfig.c b/src/win-deviceconfig.c new file mode 100644 index 000000000..ede50e060 --- /dev/null +++ b/src/win-deviceconfig.c @@ -0,0 +1,354 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "ibm.h" +#include "config.h" +#include "device.h" +#include "resources.h" +#include "win.h" + +static device_t *config_device; + +static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + int id = IDC_CONFIG_BASE; + device_config_t *config = config_device->config; + int c; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + HWND h = GetDlgItem(hdlg, id); + int val_int; + char *val_string; + int num; + char s[80]; + + switch (config->type) + { + case CONFIG_BINARY: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + SendMessage(h, BM_SETCHECK, val_int, 0); + + id++; + break; + + case CONFIG_SELECTION: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + c = 0; + while (selection->description[0]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)selection->description); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; + + case CONFIG_MIDI: + val_int = config_get_int(NULL, config->name, config->default_int); + + num = midi_get_num_devs(); + for (c = 0; c < num; c++) + { + midi_get_dev_name(c, s); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + if (val_int == c) + SendMessage(h, CB_SETCURSEL, c, 0); + } + + id += 2; + break; + } + config++; + } + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + int id = IDC_CONFIG_BASE; + device_config_t *config = config_device->config; + int c; + int changed = 0; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + HWND h = GetDlgItem(hdlg, id); + int val_int; + char *val_string; + + switch (config->type) + { + case CONFIG_BINARY: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + if (val_int != SendMessage(h, BM_GETCHECK, 0, 0)) + changed = 1; + + id++; + break; + + case CONFIG_SELECTION: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (; c > 0; c--) + selection++; + + if (val_int != selection->value) + changed = 1; + + id += 2; + break; + + case CONFIG_MIDI: + val_int = config_get_int(NULL, config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (val_int != c) + changed = 1; + + id += 2; + break; + } + config++; + } + + if (!changed) + { + EndDialog(hdlg, 0); + return TRUE; + } + + if (MessageBox(NULL, "This will reset PCem!\nOkay to continue?", "PCem", MB_OKCANCEL) != IDOK) + { + EndDialog(hdlg, 0); + return TRUE; + } + + id = IDC_CONFIG_BASE; + config = config_device->config; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + HWND h = GetDlgItem(hdlg, id); + int val_int; + char *val_string; + + switch (config->type) + { + case CONFIG_BINARY: + config_set_int(config_device->name, config->name, SendMessage(h, BM_GETCHECK, 0, 0)); + + id++; + break; + + case CONFIG_SELECTION: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_int(config_device->name, config->name, selection->value); + + id += 2; + break; + + case CONFIG_MIDI: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + config_set_int(NULL, config->name, c); + + id += 2; + break; + } + config++; + } + + saveconfig(); + + resetpchard(); + + EndDialog(hdlg, 0); + return TRUE; + } + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +void deviceconfig_open(HWND hwnd, device_t *device) +{ + device_config_t *config = device->config; + uint16_t *data_block = malloc(16384); + uint16_t *data; + DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGITEMTEMPLATE *item; + int y = 10; + int id = IDC_CONFIG_BASE; + + memset(data_block, 0, 4096); + + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; + dlg->x = 10; + dlg->y = 10; + dlg->cx = 220; + dlg->cy = 70; + + data = (uint16_t *)(dlg + 1); + + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + + *data++ = 8; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "MS Sans Serif", -1, data, 50); + + if (((unsigned long)data) & 2) + data++; + + while (config->type != -1) + { + switch (config->type) + { + case CONFIG_BINARY: + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 80; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; // no creation data + + y += 20; + break; + + case CONFIG_SELECTION: + case CONFIG_MIDI: + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; // combo box class + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; // static class + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + y += 20; + break; + } + + if (((unsigned long)data) & 2) + data++; + + config++; + } + + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; + +// DEFPUSHBUTTON "OK",IDOK,64,232,50,14, WS_TABSTOP +// PUSHBUTTON "Cancel",IDCANCEL,128,232,50,14, WS_TABSTOP + + item = (DLGITEMTEMPLATE *)data; + item->x = 20; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDOK; // OK button identifier + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + item = (DLGITEMTEMPLATE *)data; + item->x = 80; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; // OK button identifier + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); + *data++ = 0; // no creation data + + dlg->cy = y + 20; + + config_device = device; + + DialogBoxIndirect(hinstance, dlg, hwnd, deviceconfig_dlgproc); + + free(data_block); +} diff --git a/src/win-hdconf.c b/src/win-hdconf.c new file mode 100644 index 000000000..c0c288ba0 --- /dev/null +++ b/src/win-hdconf.c @@ -0,0 +1,809 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "ibm.h" +#include "ide.h" +#include "resources.h" +#include "win.h" + +static int hd_changed = 0; + +static char hd_new_name[512]; +static int hd_new_spt, hd_new_hpc, hd_new_cyl; +static int new_cdrom_channel; + +static void update_hdd_cdrom(HWND hdlg) +{ + HWND h; + + h = GetDlgItem(hdlg, IDC_CHDD); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 0) ? 0 : 1, 0); + h = GetDlgItem(hdlg, IDC_CCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 0) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_DHDD); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 1) ? 0 : 1, 0); + h = GetDlgItem(hdlg, IDC_DCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 1) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_EHDD); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 2) ? 0 : 1, 0); + h = GetDlgItem(hdlg, IDC_ECDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 2) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_FHDD); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 3) ? 0 : 1, 0); + h = GetDlgItem(hdlg, IDC_FCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 3) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_GCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 4) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_HCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 5) ? 1 : 0, 0); +} + +static BOOL CALLBACK hdnew_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char s[260]; + HWND h; + int c; + PcemHDC hd[4]; + FILE *f; + uint8_t buf[512]; + switch (message) + { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_EDIT1); + sprintf(s, "%i", 63); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT2); + sprintf(s, "%i", 16); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT3); + sprintf(s, "%i", 511); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_EDITC); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)""); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", (((511*16*63)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + h = GetDlgItem(hdlg, IDC_EDITC); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)hd_new_name); + if (!hd_new_name[0]) + { + MessageBox(ghwnd,"Please enter a valid filename","PCem error",MB_OK); + return TRUE; + } + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_cyl); + + if (hd_new_spt > 63) + { + MessageBox(ghwnd, "Drive has too many sectors (maximum is 63)", "PCem error", MB_OK); + return TRUE; + } + if (hd_new_hpc > 16) + { + MessageBox(ghwnd, "Drive has too many heads (maximum is 16)", "PCem error", MB_OK); + return TRUE; + } + if (hd_new_cyl > 16383) + { + MessageBox(ghwnd, "Drive has too many cylinders (maximum is 16383)", "PCem error", MB_OK); + return TRUE; + } + + f = fopen64(hd_new_name, "wb"); + if (!f) + { + MessageBox(ghwnd, "Can't open file for write", "PCem error", MB_OK); + return TRUE; + } + memset(buf, 0, 512); + for (c = 0; c < (hd_new_cyl * hd_new_hpc * hd_new_spt); c++) + fwrite(buf, 512, 1, f); + fclose(f); + + MessageBox(ghwnd, "Remember to partition and format the new drive", "PCem", MB_OK); + + EndDialog(hdlg, 1); + return TRUE; + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + + case IDC_CFILE: + if (!getsfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + h = GetDlgItem(hdlg, IDC_EDITC); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + } + return TRUE; + + case IDC_EDIT1: case IDC_EDIT2: case IDC_EDIT3: + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", (((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + } + break; + + } + return FALSE; +} + +BOOL CALLBACK hdsize_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char s[260]; + HWND h; + PcemHDC hd[2]; + switch (message) + { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_EDIT1); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT2); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT3); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", ((((uint64_t)hd_new_spt*(uint64_t)hd_new_hpc*(uint64_t)hd_new_cyl)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_cyl); + + if (hd_new_spt > 63) + { + MessageBox(ghwnd,"Drive has too many sectors (maximum is 63)","PCem error",MB_OK); + return TRUE; + } + if (hd_new_hpc > 16) + { + MessageBox(ghwnd,"Drive has too many heads (maximum is 16)","PCem error",MB_OK); + return TRUE; + } + if (hd_new_cyl > 16383) + { + MessageBox(ghwnd,"Drive has too many cylinders (maximum is 16383)","PCem error",MB_OK); + return TRUE; + } + + EndDialog(hdlg,1); + return TRUE; + case IDCANCEL: + EndDialog(hdlg,0); + return TRUE; + + case IDC_EDIT1: case IDC_EDIT2: case IDC_EDIT3: + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", (((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + } + break; + + } + return FALSE; +} + +static BOOL CALLBACK hdconf_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char s[260]; + HWND h; + PcemHDC hd[4]; + FILE *f; + off64_t sz; + switch (message) + { + case WM_INITDIALOG: + pause = 1; + hd[0] = hdc[0]; + hd[1] = hdc[1]; + hd[2] = hdc[2]; + hd[3] = hdc[3]; + hd_changed = 0; + + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + sprintf(s, "%i", hdc[0].spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + sprintf(s, "%i", hdc[0].hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + sprintf(s, "%i", hdc[0].tracks); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ide_fn[0]); + + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + sprintf(s, "%i", hdc[1].spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + sprintf(s, "%i", hdc[1].hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + sprintf(s, "%i", hdc[1].tracks); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h= GetDlgItem(hdlg, IDC_EDIT_D_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ide_fn[1]); + + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + sprintf(s, "%i", hdc[2].spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + sprintf(s, "%i", hdc[2].hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + sprintf(s, "%i", hdc[2].tracks); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h= GetDlgItem(hdlg, IDC_EDIT_E_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ide_fn[2]); + + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + sprintf(s, "%i", hdc[3].spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + sprintf(s, "%i", hdc[3].hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + sprintf(s, "%i", hdc[3].tracks); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h= GetDlgItem(hdlg, IDC_EDIT_F_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ide_fn[3]); + + h = GetDlgItem(hdlg, IDC_TEXT_C_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_TEXT_D_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd[1].tracks*(uint64_t)hd[1].hpc)*(uint64_t)hd[1].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_TEXT_E_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd[2].tracks*(uint64_t)hd[2].hpc)*(uint64_t)hd[2].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_TEXT_F_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd[3].tracks*(uint64_t)hd[3].hpc)*(uint64_t)hd[3].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + new_cdrom_channel = cdrom_channel; + + update_hdd_cdrom(hdlg); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + if (hd_changed || cdrom_channel != new_cdrom_channel) + { + if (MessageBox(NULL, "This will reset PCem!\nOkay to continue?", "PCem", MB_OKCANCEL) == IDOK) + { + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].spt); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].tracks); + h = GetDlgItem(hdlg, IDC_EDIT_C_FN); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ide_fn[0]); + + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].spt); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].tracks); + h = GetDlgItem(hdlg, IDC_EDIT_D_FN); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ide_fn[1]); + + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].spt); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].tracks); + h = GetDlgItem(hdlg, IDC_EDIT_E_FN); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ide_fn[2]); + + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].spt); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].tracks); + h = GetDlgItem(hdlg, IDC_EDIT_F_FN); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ide_fn[3]); + + hdc[0] = hd[0]; + hdc[1] = hd[1]; + hdc[2] = hd[2]; + hdc[3] = hd[3]; + + cdrom_channel = new_cdrom_channel; + + saveconfig(); + + resetpchard(); + } + } + case IDCANCEL: + EndDialog(hdlg, 0); + pause = 0; + return TRUE; + + case IDC_EJECTC: + hd[0].spt = 0; + hd[0].hpc = 0; + hd[0].tracks = 0; + ide_fn[0][0] = 0; + SetDlgItemText(hdlg, IDC_EDIT_C_SPT, "0"); + SetDlgItemText(hdlg, IDC_EDIT_C_HPC, "0"); + SetDlgItemText(hdlg, IDC_EDIT_C_CYL, "0"); + SetDlgItemText(hdlg, IDC_EDIT_C_FN, ""); + hd_changed = 1; + return TRUE; + case IDC_EJECTD: + hd[1].spt = 0; + hd[1].hpc = 0; + hd[1].tracks = 0; + ide_fn[1][0] = 0; + SetDlgItemText(hdlg, IDC_EDIT_D_SPT, "0"); + SetDlgItemText(hdlg, IDC_EDIT_D_HPC, "0"); + SetDlgItemText(hdlg, IDC_EDIT_D_CYL, "0"); + SetDlgItemText(hdlg, IDC_EDIT_D_FN, ""); + hd_changed = 1; + return TRUE; + case IDC_EJECTE: + hd[2].spt = 0; + hd[2].hpc = 0; + hd[2].tracks = 0; + ide_fn[2][0] = 0; + SetDlgItemText(hdlg, IDC_EDIT_E_SPT, "0"); + SetDlgItemText(hdlg, IDC_EDIT_E_HPC, "0"); + SetDlgItemText(hdlg, IDC_EDIT_E_CYL, "0"); + SetDlgItemText(hdlg, IDC_EDIT_E_FN, ""); + hd_changed = 1; + return TRUE; + case IDC_EJECTF: + hd[3].spt = 0; + hd[3].hpc = 0; + hd[3].tracks = 0; + ide_fn[3][0] = 0; + SetDlgItemText(hdlg, IDC_EDIT_F_SPT, "0"); + SetDlgItemText(hdlg, IDC_EDIT_F_HPC, "0"); + SetDlgItemText(hdlg, IDC_EDIT_F_CYL, "0"); + SetDlgItemText(hdlg, IDC_EDIT_F_FN, ""); + hd_changed = 1; + return TRUE; + + case IDC_CNEW: + if (DialogBox(hinstance, TEXT("HdNewDlg"), hdlg, hdnew_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)hd_new_name); + + h = GetDlgItem(hdlg, IDC_TEXT_C_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_CFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, hdsize_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + + h= GetDlgItem(hdlg, IDC_TEXT_C_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_DNEW: + if (DialogBox(hinstance, TEXT("HdNewDlg"), hdlg, hdnew_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)hd_new_name); + + h= GetDlgItem(hdlg, IDC_TEXT_D_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_DFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, hdsize_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + + h = GetDlgItem(hdlg, IDC_TEXT_D_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_ENEW: + if (DialogBox(hinstance, TEXT("HdNewDlg"), hdlg, hdnew_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)hd_new_name); + + h= GetDlgItem(hdlg, IDC_TEXT_E_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_EFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, hdsize_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + + h = GetDlgItem(hdlg, IDC_TEXT_E_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_FNEW: + if (DialogBox(hinstance, TEXT("HdNewDlg"), hdlg, hdnew_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)hd_new_name); + + h= GetDlgItem(hdlg, IDC_TEXT_F_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_FFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, hdsize_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + + h = GetDlgItem(hdlg, IDC_TEXT_F_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_EDIT_C_SPT: case IDC_EDIT_C_HPC: case IDC_EDIT_C_CYL: + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].spt); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT_C_SIZE); + sprintf(s, "Size : %imb", ((((hd[0].tracks*hd[0].hpc)*hd[0].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + + case IDC_EDIT_D_SPT: case IDC_EDIT_D_HPC: case IDC_EDIT_D_CYL: + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].spt); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT_D_SIZE); + sprintf(s, "Size : %imb", ((((hd[1].tracks*hd[1].hpc)*hd[1].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + + case IDC_EDIT_E_SPT: case IDC_EDIT_E_HPC: case IDC_EDIT_E_CYL: + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].spt); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT_E_SIZE); + sprintf(s, "Size : %imb", ((((hd[2].tracks*hd[2].hpc)*hd[2].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + + case IDC_EDIT_F_SPT: case IDC_EDIT_F_HPC: case IDC_EDIT_F_CYL: + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].spt); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT_F_SIZE); + sprintf(s, "Size : %imb", ((((hd[3].tracks*hd[3].hpc)*hd[3].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + + case IDC_CHDD: + if (new_cdrom_channel == 0) + new_cdrom_channel = -1; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_DHDD: + if (new_cdrom_channel == 1) + new_cdrom_channel = -1; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_EHDD: + if (new_cdrom_channel == 2) + new_cdrom_channel = -1; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_FHDD: + if (new_cdrom_channel == 3) + new_cdrom_channel = -1; + update_hdd_cdrom(hdlg); + return TRUE; + + case IDC_CCDROM: + new_cdrom_channel = 0; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_DCDROM: + new_cdrom_channel = 1; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_ECDROM: + new_cdrom_channel = 2; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_FCDROM: + new_cdrom_channel = 3; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_GCDROM: + new_cdrom_channel = 4; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_HCDROM: + new_cdrom_channel = 5; + update_hdd_cdrom(hdlg); + return TRUE; + } + break; + + } + return FALSE; +} + +void hdconf_open(HWND hwnd) +{ + DialogBox(hinstance, TEXT("HdConfDlg"), hwnd, hdconf_dlgproc); +} diff --git a/src/win-joystick.cc b/src/win-joystick.cc new file mode 100644 index 000000000..55e3206f2 --- /dev/null +++ b/src/win-joystick.cc @@ -0,0 +1,255 @@ +#define DIRECTINPUT_VERSION 0x0800 +#include +#include +#include +extern "C" { +#include "device.h" +#include "gameport.h" +} +#include "plat-joystick.h" +#include "win.h" + +extern "C" int video_fullscreen; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void joystick_init(); +extern "C" void joystick_close(); +extern "C" void poll_joystick(); + +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; + +static LPDIRECTINPUT8 lpdi; +static LPDIRECTINPUTDEVICE8 lpdi_joystick[2] = {NULL, NULL}; + +int joysticks_present = 0; +static GUID joystick_guids[MAX_JOYSTICKS]; + +static BOOL CALLBACK joystick_enum_callback(LPCDIDEVICEINSTANCE lpddi, LPVOID data) +{ + if (joysticks_present >= MAX_JOYSTICKS) + return DIENUM_STOP; + + pclog("joystick_enum_callback : found joystick %i : %s\n", joysticks_present, lpddi->tszProductName); + + joystick_guids[joysticks_present++] = lpddi->guidInstance; + + if (joysticks_present >= MAX_JOYSTICKS) + return DIENUM_STOP; + + return DIENUM_CONTINUE; +} + +BOOL CALLBACK DIEnumDeviceObjectsCallback( + LPCDIDEVICEOBJECTINSTANCE lpddoi, + LPVOID pvRef) +{ + plat_joystick_t *state = (plat_joystick_t *)pvRef; + + if (lpddoi->guidType == GUID_XAxis || lpddoi->guidType == GUID_YAxis || lpddoi->guidType == GUID_ZAxis || + lpddoi->guidType == GUID_RxAxis || lpddoi->guidType == GUID_RyAxis || lpddoi->guidType == GUID_RzAxis || + lpddoi->guidType == GUID_Slider) + { + strncpy(state->axis[state->nr_axes].name, lpddoi->tszName, sizeof(state->axis[state->nr_axes].name)); + pclog("Axis %i : %s %x %x\n", state->nr_axes, state->axis[state->nr_axes].name, lpddoi->dwOfs, lpddoi->dwType); + if (lpddoi->guidType == GUID_XAxis) + state->axis[state->nr_axes].id = 0; + else if (lpddoi->guidType == GUID_YAxis) + state->axis[state->nr_axes].id = 1; + else if (lpddoi->guidType == GUID_ZAxis) + state->axis[state->nr_axes].id = 2; + else if (lpddoi->guidType == GUID_RxAxis) + state->axis[state->nr_axes].id = 3; + else if (lpddoi->guidType == GUID_RyAxis) + state->axis[state->nr_axes].id = 4; + else if (lpddoi->guidType == GUID_RzAxis) + state->axis[state->nr_axes].id = 5; + state->nr_axes++; + } + else if (lpddoi->guidType == GUID_Button) + { + strncpy(state->button[state->nr_buttons].name, lpddoi->tszName, sizeof(state->button[state->nr_buttons].name)); + pclog("Button %i : %s %x %x\n", state->nr_buttons, state->button[state->nr_buttons].name, lpddoi->dwOfs, lpddoi->dwType); + state->nr_buttons++; + } + else if (lpddoi->guidType == GUID_POV) + { + strncpy(state->pov[state->nr_povs].name, lpddoi->tszName, sizeof(state->pov[state->nr_povs].name)); + pclog("POV %i : %s %x %x\n", state->nr_povs, state->pov[state->nr_povs].name, lpddoi->dwOfs, lpddoi->dwType); + state->nr_povs++; + } + + return DIENUM_CONTINUE; +} + +void joystick_init() +{ + int c; + + atexit(joystick_close); + + joysticks_present = 0; + + if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **) &lpdi, NULL))) + fatal("joystick_init : DirectInputCreate failed\n"); + + if (FAILED(lpdi->EnumDevices(DIDEVTYPE_JOYSTICK, joystick_enum_callback, NULL, DIEDFL_ATTACHEDONLY))) + fatal("joystick_init : EnumDevices failed\n"); + + pclog("joystick_init: joysticks_present=%i\n", joysticks_present); + + for (c = 0; c < joysticks_present; c++) + { + LPDIRECTINPUTDEVICE8 lpdi_joystick_temp = NULL; + DIPROPRANGE joy_axis_range; + DIDEVICEINSTANCE device_instance; + DIDEVCAPS devcaps; + int d; + + if (FAILED(lpdi->CreateDevice(joystick_guids[c], &lpdi_joystick_temp, NULL))) + fatal("joystick_init : CreateDevice failed\n"); + if (FAILED(lpdi_joystick_temp->QueryInterface(IID_IDirectInputDevice8, (void **)&lpdi_joystick[c]))) + fatal("joystick_init : CreateDevice failed\n"); + lpdi_joystick_temp->Release(); + + memset(&device_instance, 0, sizeof(device_instance)); + device_instance.dwSize = sizeof(device_instance); + if (FAILED(lpdi_joystick[c]->GetDeviceInfo(&device_instance))) + fatal("joystick_init : GetDeviceInfo failed\n"); + pclog("Joystick %i :\n", c); + pclog(" tszInstanceName = %s\n", device_instance.tszInstanceName); + pclog(" tszProductName = %s\n", device_instance.tszProductName); + strncpy(plat_joystick_state[c].name, device_instance.tszInstanceName, 64); + + memset(&devcaps, 0, sizeof(devcaps)); + devcaps.dwSize = sizeof(devcaps); + if (FAILED(lpdi_joystick[c]->GetCapabilities(&devcaps))) + fatal("joystick_init : GetCapabilities failed\n"); + pclog(" Axes = %i\n", devcaps.dwAxes); + pclog(" Buttons = %i\n", devcaps.dwButtons); + pclog(" POVs = %i\n", devcaps.dwPOVs); + + lpdi_joystick[c]->EnumObjects(DIEnumDeviceObjectsCallback, &plat_joystick_state[c], DIDFT_ALL); + + if (FAILED(lpdi_joystick[c]->SetCooperativeLevel(ghwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + fatal("joystick_init : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_joystick[c]->SetDataFormat(&c_dfDIJoystick))) + fatal("joystick_init : SetDataFormat failed\n"); + + joy_axis_range.lMin = -32768; + joy_axis_range.lMax = 32767; + joy_axis_range.diph.dwSize = sizeof(DIPROPRANGE); + joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + joy_axis_range.diph.dwHow = DIPH_BYOFFSET; + joy_axis_range.diph.dwObj = DIJOFS_X; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_Y; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_Z; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RX; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RY; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RZ; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + + if (FAILED(lpdi_joystick[c]->Acquire())) + fatal("joystick_init : Acquire failed\n"); + } +} + +void joystick_close() +{ + if (lpdi_joystick[1]) + { + lpdi_joystick[1]->Release(); + lpdi_joystick[1] = NULL; + } + if (lpdi_joystick[0]) + { + lpdi_joystick[0]->Release(); + lpdi_joystick[0] = NULL; + } +} + +void joystick_poll() +{ + int c, d; + + for (c = 0; c < joysticks_present; c++) + { + DIJOYSTATE joystate; + int b; + + if (FAILED(lpdi_joystick[c]->Poll())) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + } + if (FAILED(lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate))) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate); + } + + plat_joystick_state[c].a[0] = joystate.lX; + plat_joystick_state[c].a[1] = joystate.lY; + plat_joystick_state[c].a[2] = joystate.lZ; + plat_joystick_state[c].a[3] = joystate.lRx; + plat_joystick_state[c].a[4] = joystate.lRy; + plat_joystick_state[c].a[5] = joystate.lRz; + + for (b = 0; b < 16; b++) + plat_joystick_state[c].b[b] = joystate.rgbButtons[b] & 0x80; + + for (b = 0; b < 4; b++) + plat_joystick_state[c].p[b] = joystate.rgdwPOV[b]; +// pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", c, joystick_state[c].x, joystick_state[c].y, joystick_state[c].b[0], joystick_state[c].b[1], joysticks_present); + } + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + if (joystick_state[c].plat_joystick_nr) + { + int joystick_nr = joystick_state[c].plat_joystick_nr - 1; + + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + { + if (joystick_state[c].axis_mapping[d] & POV_X) + { + int pov = plat_joystick_state[joystick_nr].p[joystick_state[c].axis_mapping[d] & 3]; + + if (LOWORD(pov) == 0xFFFF) + joystick_state[c].axis[d] = 0; + else + joystick_state[c].axis[d] = sin((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else if (joystick_state[c].axis_mapping[d] & POV_Y) + { + int pov = plat_joystick_state[joystick_nr].p[joystick_state[c].axis_mapping[d] & 3]; + + if (LOWORD(pov) == 0xFFFF) + joystick_state[c].axis[d] = 0; + else + joystick_state[c].axis[d] = -cos((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else + joystick_state[c].axis[d] = plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[joystick_state[c].axis_mapping[d]].id]; + } + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]]; + } + else + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = 0; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = 0; + } + } +} + diff --git a/src/win-joystickconfig.c b/src/win-joystickconfig.c new file mode 100644 index 000000000..4aff40248 --- /dev/null +++ b/src/win-joystickconfig.c @@ -0,0 +1,407 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "ibm.h" +#include "config.h" +#include "device.h" +#include "gameport.h" +#include "plat-joystick.h" +#include "resources.h" +#include "win.h" + +static int joystick_nr; +static int joystick_config_type; +#define AXIS_STRINGS_MAX 3 +static char *axis_strings[AXIS_STRINGS_MAX] = {"X Axis", "Y Axis", "Z Axis"}; + +static void rebuild_axis_button_selections(HWND hdlg) +{ + int id = IDC_CONFIG_BASE + 2; + HWND h; + int joystick; + int c, d; + + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int sel = c; + + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].axis[d].name); + if (c < AXIS_STRINGS_MAX) + { + if (!stricmp(axis_strings[c], plat_joystick_state[joystick-1].axis[d].name)) + sel = d; + } + } + for (d = 0; d < plat_joystick_state[joystick-1].nr_povs; d++) + { + char s[80]; + + sprintf(s, "%s (X axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + } + SendMessage(h, CB_SETCURSEL, sel, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } + + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_buttons; d++) + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].button[d].name); + SendMessage(h, CB_SETCURSEL, c, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } +} + +static int get_axis(HWND hdlg, int id) +{ + HWND h = GetDlgItem(hdlg, id); + int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0); + int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_axes; + + if (axis_sel < nr_axes) + return axis_sel; + + axis_sel -= nr_axes; + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); +} + +static BOOL CALLBACK joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + HWND h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + int c, d; + int id = IDC_CONFIG_BASE + 2; + int joystick = joystick_state[joystick_nr].plat_joystick_nr; + + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); + + for (c = 0; c < joysticks_present; c++) + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[c].name); + + SendMessage(h, CB_SETCURSEL, joystick, 0); + + rebuild_axis_button_selections(hdlg); + + if (joystick_state[joystick_nr].plat_joystick_nr) + { + int nr_axes = plat_joystick_state[joystick-1].nr_axes; + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int mapping = joystick_state[joystick_nr].axis_mapping[c]; + + h = GetDlgItem(hdlg, id); + if (mapping & POV_X) + SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2, 0); + else if (mapping & POV_Y) + SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2 + 1, 0); + else + SendMessage(h, CB_SETCURSEL, mapping, 0); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_SETCURSEL, joystick_state[joystick_nr].button_mapping[c], 0); + id += 2; + } + } + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CONFIG_BASE: + if (HIWORD(wParam) == CBN_SELCHANGE) + rebuild_axis_button_selections(hdlg); + break; + + case IDOK: + { + HWND h; + int joystick; + int c, d; + int id = IDC_CONFIG_BASE + 2; + + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + joystick_state[joystick_nr].plat_joystick_nr = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (joystick_state[joystick_nr].plat_joystick_nr) + { + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + joystick_state[joystick_nr].axis_mapping[c] = get_axis(hdlg, id); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + joystick_state[joystick_nr].button_mapping[c] = SendMessage(h, CB_GETCURSEL, 0, 0); + id += 2; + } + } + } + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +void joystickconfig_open(HWND hwnd, int joy_nr, int type) +{ +// device_config_t *config = device->config; + uint16_t *data_block = malloc(16384); + uint16_t *data; + DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGITEMTEMPLATE *item; + int y = 10; + int id = IDC_CONFIG_BASE; + int c; + + joystick_nr = joy_nr; + joystick_config_type = type; + + memset(data_block, 0, 4096); + + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; + dlg->x = 10; + dlg->y = 10; + dlg->cx = 220; + dlg->cy = 70; + + data = (uint16_t *)(dlg + 1); + + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + + *data++ = 8; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "MS Sans Serif", -1, data, 50); + + if (((unsigned long)data) & 2) + data++; + + + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; // combo box class + + data += MultiByteToWideChar(CP_ACP, 0, "Device", -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; // static class + + data += MultiByteToWideChar(CP_ACP, 0, "Device :", -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + y += 20; + + + for (c = 0; c < joystick_get_axis_count(type); c++) + { + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; // combo box class + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; // static class + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + y += 20; + } + + for (c = 0; c < joystick_get_button_count(type); c++) + { + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; // combo box class + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; // static class + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + y += 20; + } + + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; + +// DEFPUSHBUTTON "OK",IDOK,64,232,50,14, WS_TABSTOP +// PUSHBUTTON "Cancel",IDCANCEL,128,232,50,14, WS_TABSTOP + + item = (DLGITEMTEMPLATE *)data; + item->x = 20; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDOK; // OK button identifier + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + item = (DLGITEMTEMPLATE *)data; + item->x = 80; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; // OK button identifier + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); + *data++ = 0; // no creation data + + dlg->cy = y + 20; + +// config_device = device; + + DialogBoxIndirect(hinstance, dlg, hwnd, joystickconfig_dlgproc); + + free(data_block); +} diff --git a/src/win-keyboard.cc b/src/win-keyboard.cc new file mode 100644 index 000000000..6cd5723e6 --- /dev/null +++ b/src/win-keyboard.cc @@ -0,0 +1,57 @@ +#define UNICODE +#include +#include +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "plat-keyboard.h" +#include "win.h" +#include "video.h" + +extern "C" int pcem_key[272]; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void keyboard_init(); +extern "C" void keyboard_close(); +extern "C" void keyboard_poll(); + +int pcem_key[272]; + +void keyboard_init() +{ + atexit(keyboard_close); + + memset(pcem_key, 0, sizeof(pcem_key)); + pclog("Keyboard initialized!\n"); +} + +void keyboard_close() +{ +} + +void keyboard_poll_host() +{ +#if 0 + int c; + + for (c = 0; c < 272; c++) + pcem_key[c] = rawinputkey[c]; + + if ((rawinputkey[0x1D] || rawinputkey[0x9D]) && + (rawinputkey[0x38] || rawinputkey[0xB8]) && + (rawinputkey[0x51] || rawinputkey[0xD1]) && + video_fullscreen) + leave_fullscreen(); + + if ((rawinputkey[0x1D] || rawinputkey[0x9D]) && +// (rawinputkey[0x38] || rawinputkey[0xB8]) && + (rawinputkey[0x57] || rawinputkey[0x57])) + { + pclog("Taking screenshot...\n"); + take_screenshot(); + } +#endif +} diff --git a/src/win-midi.c b/src/win-midi.c new file mode 100644 index 000000000..ba8965102 --- /dev/null +++ b/src/win-midi.c @@ -0,0 +1,113 @@ +#include +#include +#include "ibm.h" +#include "plat-midi.h" + +static int midi_id; +static HMIDIOUT midi_out_device = NULL; + +void midi_close(); + +void midi_init() +{ + int c; + int n; + MIDIOUTCAPS ocaps; + MMRESULT hr; + + midi_id = config_get_int(NULL, "midi", 0); + + hr = midiOutOpen(&midi_out_device, midi_id, 0, + 0, CALLBACK_NULL); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + midi_id = 0; + hr = midiOutOpen(&midi_out_device, midi_id, 0, + 0, CALLBACK_NULL); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + return; + } + } + + midiOutReset(midi_out_device); +} + +void midi_close() +{ + if (midi_out_device != NULL) + { + midiOutReset(midi_out_device); + midiOutClose(midi_out_device); + midi_out_device = NULL; + } +} + +int midi_get_num_devs() +{ + return midiOutGetNumDevs(); +} +void midi_get_dev_name(int num, char *s) +{ + MIDIOUTCAPS caps; + + midiOutGetDevCaps(num, &caps, sizeof(caps)); + strcpy(s, caps.szPname); +} + +static int midi_pos, midi_len; +static uint32_t midi_command; +static int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 1}; +static int midi_insysex; +static uint8_t midi_sysex_data[1024+2]; + +static void midi_send_sysex() +{ + MIDIHDR hdr; + int c; + + hdr.lpData = midi_sysex_data; + hdr.dwBufferLength = midi_pos; + hdr.dwFlags = 0; + +/* pclog("Sending sysex : "); + for (c = 0; c < midi_pos; c++) + pclog("%02x ", midi_sysex_data[c]); + pclog("\n");*/ + + midiOutPrepareHeader(midi_out_device, &hdr, sizeof(MIDIHDR)); + midiOutLongMsg(midi_out_device, &hdr, sizeof(MIDIHDR)); + + midi_insysex = 0; +} + +void midi_write(uint8_t val) +{ + if ((val & 0x80) && !(val == 0xf7 && midi_insysex)) + { + midi_pos = 0; + midi_len = midi_lengths[(val >> 4) & 7]; + midi_command = 0; + if (val == 0xf0) + midi_insysex = 1; + } + + if (midi_insysex) + { + midi_sysex_data[midi_pos++] = val; + + if (val == 0xf7 || midi_pos >= 1024+2) + midi_send_sysex(); + return; + } + + if (midi_len) + { + midi_command |= (val << (midi_pos * 8)); + + midi_pos++; + + if (midi_pos == midi_len) + midiOutShortMsg(midi_out_device, midi_command); + } +} diff --git a/src/win-mouse.cc b/src/win-mouse.cc new file mode 100644 index 000000000..e769c7a45 --- /dev/null +++ b/src/win-mouse.cc @@ -0,0 +1,70 @@ +#define DIRECTINPUT_VERSION 0x0800 +#include +#include "plat-mouse.h" +#include "win.h" + +extern "C" int video_fullscreen; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void mouse_init(); +extern "C" void mouse_close(); +extern "C" void mouse_poll_host(); +extern "C" void mouse_get_mickeys(int *x, int *y); + +static LPDIRECTINPUT8 lpdi; +static LPDIRECTINPUTDEVICE8 lpdi_mouse = NULL; +static DIMOUSESTATE mousestate; +static int mouse_x = 0, mouse_y = 0; +int mouse_buttons = 0; + +void mouse_init() +{ + atexit(mouse_close); + + if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **) &lpdi, NULL))) + fatal("mouse_init : DirectInputCreate failed\n"); + if (FAILED(lpdi->CreateDevice(GUID_SysMouse, &lpdi_mouse, NULL))) + fatal("mouse_init : CreateDevice failed\n"); + if (FAILED(lpdi_mouse->SetCooperativeLevel(ghwnd, DISCL_FOREGROUND | (video_fullscreen ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE)))) + fatal("mouse_init : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_mouse->SetDataFormat(&c_dfDIMouse))) + fatal("mouse_init : SetDataFormat failed\n"); +} + +void mouse_close() +{ + if (lpdi_mouse) + { + lpdi_mouse->Release(); + lpdi_mouse = NULL; + } +} + +void mouse_poll_host() +{ + if (FAILED(lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate))) + { + lpdi_mouse->Acquire(); + lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate); + } + mouse_buttons = 0; + if (mousestate.rgbButtons[0] & 0x80) + mouse_buttons |= 1; + if (mousestate.rgbButtons[1] & 0x80) + mouse_buttons |= 2; + if (mousestate.rgbButtons[2] & 0x80) + mouse_buttons |= 4; + mouse_x += mousestate.lX; + mouse_y += mousestate.lY; + if (!mousecapture && !video_fullscreen) + mouse_x = mouse_y = mouse_buttons = 0; +} + +void mouse_get_mickeys(int *x, int *y) +{ + *x = mouse_x; + *y = mouse_y; + mouse_x = mouse_y = 0; +} diff --git a/src/win-status.c b/src/win-status.c new file mode 100644 index 000000000..8d7e1f09d --- /dev/null +++ b/src/win-status.c @@ -0,0 +1,103 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "ibm.h" +#include "device.h" +#include "video.h" +#include "resources.h" +#include "win.h" +#include "x86_ops.h" +#include "mem.h" +#include "codegen.h" + +HWND status_hwnd; +int status_is_open = 0; + +extern int sreadlnum, swritelnum, segareads, segawrites, scycles_lost; + +extern uint64_t main_time; +static uint64_t status_time; + +static BOOL CALLBACK status_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char device_s[4096]; + switch (message) + { + case WM_INITDIALOG: + status_is_open = 1; + case WM_USER: + { + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + status_time = new_time; + sprintf(device_s, + "CPU speed : %f MIPS\n" + "FPU speed : %f MFLOPS\n\n" + +/* "Cache misses (read) : %i/sec\n" + "Cache misses (write) : %i/sec\n\n"*/ + + "Video throughput (read) : %i bytes/sec\n" + "Video throughput (write) : %i bytes/sec\n\n" + "Effective clockspeed : %iHz\n\n" + "Timer 0 frequency : %fHz\n\n" + "CPU time : %f%% (%f%%)\n" + + "New blocks : %i\nOld blocks : %i\nRecompiled speed : %f MIPS\nAverage size : %f\n" + "Flushes : %i\nEvicted : %i\nReused : %i\nRemoved : %i\nReal speed : %f MIPS" +// "\nFully recompiled ins %% : %f%%" + ,mips, + flops, +/*#ifndef DYNAREC + sreadlnum, + swritelnum, +#endif*/ + segareads, + segawrites, + clockrate - (sreadlnum*memwaitstate) - (swritelnum*memwaitstate) - scycles_lost, + pit_timer0_freq(), + ((double)main_time * 100.0) / status_diff, + ((double)main_time * 100.0) / timer_freq + + , cpu_new_blocks_latched, cpu_recomp_blocks_latched, (double)cpu_recomp_ins_latched / 1000000.0, (double)cpu_recomp_ins_latched/cpu_recomp_blocks_latched, + cpu_recomp_flushes_latched, cpu_recomp_evicted_latched, + cpu_recomp_reuse_latched, cpu_recomp_removed_latched, + + ((double)cpu_recomp_ins_latched / 1000000.0) / ((double)main_time / timer_freq) +// ((double)cpu_recomp_full_ins_latched / (double)cpu_recomp_ins_latched) * 100.0 +// cpu_reps_latched, cpu_notreps_latched + ); + main_time = 0; +/*#ifndef DYNAREC + device_add_status_info(device_s, 4096); +#endif*/ + SendDlgItemMessage(hdlg, IDC_STEXT_DEVICE, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); + + device_s[0] = 0; + device_add_status_info(device_s, 4096); + SendDlgItemMessage(hdlg, IDC_STEXT1, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + status_is_open = 0; + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + + return FALSE; +} + +void status_open(HWND hwnd) +{ + status_hwnd = CreateDialog(hinstance, TEXT("StatusDlg"), hwnd, status_dlgproc); + ShowWindow(status_hwnd, SW_SHOW); +} diff --git a/src/win-time.c b/src/win-time.c new file mode 100644 index 000000000..4075bbf12 --- /dev/null +++ b/src/win-time.c @@ -0,0 +1,48 @@ +#include +#include "ibm.h" +#include "nvr.h" + +void time_sleep(int count) +{ + Sleep(count); +} + +void time_get(char *nvrram) +{ + SYSTEMTIME systemtime; + int c, d; + uint8_t baknvr[10]; + + memcpy(baknvr,nvrram,10); + GetLocalTime(&systemtime); + + d = systemtime.wSecond % 10; + c = systemtime.wSecond / 10; + nvrram[0] = d | (c << 4); + d = systemtime.wMinute % 10; + c = systemtime.wMinute / 10; + nvrram[2] = d | (c << 4); + d = systemtime.wHour % 10; + c = systemtime.wHour / 10; + nvrram[4] = d | (c << 4); + d = systemtime.wDayOfWeek % 10; + c = systemtime.wDayOfWeek / 10; + nvrram[6] = d | (c << 4); + d = systemtime.wDay % 10; + c = systemtime.wDay / 10; + nvrram[7] = d | (c << 4); + d = systemtime.wMonth % 10; + c = systemtime.wMonth / 10; + nvrram[8] = d | (c << 4); + d = systemtime.wYear % 10; + c = (systemtime.wYear / 10) % 10; + nvrram[9] = d | (c << 4); + if (baknvr[0] != nvrram[0] || + baknvr[2] != nvrram[2] || + baknvr[4] != nvrram[4] || + baknvr[6] != nvrram[6] || + baknvr[7] != nvrram[7] || + baknvr[8] != nvrram[8] || + baknvr[9] != nvrram[9]) + nvrram[0xA]|=0x80; +} diff --git a/src/win-video.c b/src/win-video.c new file mode 100644 index 000000000..c1202d17a --- /dev/null +++ b/src/win-video.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include "video.h" + +BITMAP *screen; + +void hline(BITMAP *b, int x1, int y, int x2, uint32_t col) +{ + if (y < 0 || y >= buffer->h) + return; + + if (b == buffer) + memset(&b->line[y][x1], col, x2 - x1); + else + memset(&((uint32_t *)b->line[y])[x1], col, (x2 - x1) * 4); +} + +void blit(BITMAP *src, BITMAP *dst, int x1, int y1, int x2, int y2, int xs, int ys) +{ +} + +void stretch_blit(BITMAP *src, BITMAP *dst, int x1, int y1, int xs1, int ys1, int x2, int y2, int xs2, int ys2) +{ +} + +void rectfill(BITMAP *b, int x1, int y1, int x2, int y2, uint32_t col) +{ +} + +void set_palette(PALETTE p) +{ +} + +void destroy_bitmap(BITMAP *b) +{ +} + +BITMAP *create_bitmap(int x, int y) +{ + BITMAP *b = malloc(sizeof(BITMAP) + (y * sizeof(uint8_t *))); + int c; + b->dat = malloc(x * y * 4); + for (c = 0; c < y; c++) + { + b->line[c] = b->dat + (c * x * 4); + } + b->w = x; + b->h = y; + return b; +} diff --git a/src/win.c b/src/win.c new file mode 100644 index 000000000..ef370606c --- /dev/null +++ b/src/win.c @@ -0,0 +1,1487 @@ +#define _WIN32_WINNT 0x0501 +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include +#include + +#include + +#include +#include +#include +#include +#include "ibm.h" +#include "cdrom-null.h" +#include "cdrom-ioctl.h" +#include "cdrom-iso.h" +#include "config.h" +#include "video.h" +#include "resources.h" +#include "cpu.h" +#include "ide.h" +#include "model.h" +#include "nethandler.h" +#include "nvr.h" +#include "sound.h" +#include "thread.h" +#include "disc.h" + +#include "plat-midi.h" +#include "plat-keyboard.h" + +#include "win.h" +#include "win-ddraw.h" +#include "win-ddraw-fs.h" +#include "win-d3d.h" +#include "win-d3d-fs.h" +//#include "win-opengl.h" + +#ifndef MAPVK_VK_TO_VSC +#define MAPVK_VK_TO_VSC 0 +#endif + +static int save_window_pos = 0; +uint64_t timer_freq; + +int rawinputkey[272]; + +static RAWINPUTDEVICE device; +static uint16_t scancode_map[65536]; + +static struct +{ + void (*init)(HWND h); + void (*close)(); + void (*resize)(int x, int y); +} vid_apis[2][2] = +{ + { + ddraw_init, ddraw_close, NULL, + d3d_init, d3d_close, d3d_resize + }, + { + ddraw_fs_init, ddraw_fs_close, NULL, + d3d_fs_init, d3d_fs_close, NULL + }, +}; + +#define TIMER_1SEC 1 + +int winsizex=640,winsizey=480; +int efwinsizey=480; +int gfx_present[GFX_MAX]; +#undef cs +CRITICAL_SECTION cs; + +HANDLE mainthreadh; + +int infocus=1; + +int drawits=0; + +int romspresent[ROM_MAX]; +int quited=0; + +RECT oldclip; +int mousecapture=0; + +/* Declare Windows procedure */ +LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +HWND ghwnd; + +HINSTANCE hinstance; + +HMENU menu; + +extern int updatestatus; + +int pause=0; + +static int win_doresize = 0; + +static int leave_fullscreen_flag = 0; + +void updatewindowsize(int x, int y) +{ + RECT r; + if (vid_resize) return; + + if (x < 160) x = 160; + if (y < 100) y = 100; + + winsizex=x; efwinsizey=y; + + if (force_43) + { + /* Account for possible overscan. */ + if (overscan_y == 16) + { + /* CGA */ + winsizey = ((int) (((double) (x - overscan_x) / 4.0) * 3.0)) + overscan_y; + } + else if (overscan_y < 16) + { + /* MDA/Hercules */ + winsizey = efwinsizey; + } + else + { + if (enable_overscan) + { + /* EGA/(S)VGA with overscan */ + winsizey = ((int) (((double) (x - overscan_x) / 4.0) * 3.0)) + overscan_y; + } + else + { + /* EGA/(S)VGA without overscan */ + winsizey = efwinsizey; + } + } + } + else + { + winsizey = efwinsizey; + } + + win_doresize = 1; +} + +void uws_natural() +{ + updatewindowsize(winsizex, efwinsizey); +} + +void releasemouse() +{ + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture = 0; + } +} + +void startblit() +{ + EnterCriticalSection(&cs); +} + +void endblit() +{ + LeaveCriticalSection(&cs); +} + +void leave_fullscreen() +{ + leave_fullscreen_flag = 1; +} + +uint64_t main_time; + +void mainthread(LPVOID param) +{ + int t = 0; + int frames = 0; + DWORD old_time, new_time; + +// Sleep(500); + drawits=0; + old_time = GetTickCount(); + while (!quited) + { + if (updatestatus) + { + updatestatus = 0; + if (status_is_open) + SendMessage(status_hwnd, WM_USER, 0, 0); + } + new_time = GetTickCount(); + drawits += new_time - old_time; + old_time = new_time; + if (drawits > 0 && !pause) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + drawits-=10; if (drawits>50) drawits=0; + runpc(); + frames++; + if (frames >= 200 && nvr_dosave) + { + frames = 0; + nvr_dosave = 0; + savenvr(); + } + end_time = timer_read(); + main_time += end_time - start_time; + } + else + Sleep(1); + + if (!video_fullscreen && win_doresize) + { + RECT r; + GetWindowRect(ghwnd, &r); + MoveWindow(ghwnd, r.left, r.top, + winsizex + (GetSystemMetrics(SM_CXFIXEDFRAME) * 2), + winsizey + (GetSystemMetrics(SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 1, + TRUE); + win_doresize = 0; + } + + if (leave_fullscreen_flag) + { + leave_fullscreen_flag = 0; + SendMessage(ghwnd, WM_LEAVEFULLSCREEN, 0, 0); + } + if (video_fullscreen && infocus) + { + SetCursorPos(9999, 9999); + } + } +} + +void *thread_create(void (*thread_rout)(void *param), void *param) +{ + return (void *)_beginthread(thread_rout, 0, param); +} + +void thread_kill(void *handle) +{ + TerminateThread(handle, 0); +} + +void thread_sleep(int t) +{ + Sleep(t); +} + +typedef struct win_event_t +{ + HANDLE handle; +} win_event_t; + +event_t *thread_create_event() +{ + win_event_t *event = malloc(sizeof(win_event_t)); + + event->handle = CreateEvent(NULL, FALSE, FALSE, NULL); + + return (event_t *)event; +} + +void thread_set_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + SetEvent(event->handle); +} + +void thread_reset_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + ResetEvent(event->handle); +} + +int thread_wait_event(event_t *_event, int timeout) +{ + win_event_t *event = (win_event_t *)_event; + + if (timeout == -1) + timeout = INFINITE; + + if (WaitForSingleObject(event->handle, timeout)) + return 1; + return 0; +} + +void thread_destroy_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + CloseHandle(event->handle); + + free(event); +} + +static void initmenu(void) +{ + int c; + HMENU m; + char s[32]; + m=GetSubMenu(menu,2); /*Settings*/ + m=GetSubMenu(m,1); /*CD-ROM*/ + + /* Loop through each Windows drive letter and test to see if + it's a CDROM */ + for (c='A';c<='Z';c++) + { + sprintf(s,"%c:\\",c); + if (GetDriveType(s)==DRIVE_CDROM) + { + sprintf(s, "Host CD/DVD Drive (%c:)", c); + AppendMenu(m,MF_STRING,IDM_CDROM_REAL+c,s); + } + } +} + +void get_executable_name(char *s, int size) +{ + GetModuleFileName(hinstance, s, size); +} + +void set_window_title(char *s) +{ + if (video_fullscreen) + return; + SetWindowText(ghwnd, s); +} + +uint64_t timer_read() +{ + LARGE_INTEGER qpc_time; + QueryPerformanceCounter(&qpc_time); + return qpc_time.QuadPart; +} + +/* This is so we can disambiguate scan codes that would otherwise conflict and get + passed on incorrectly. */ +UINT16 convert_scan_code(UINT16 scan_code) +{ + switch (scan_code) + { + case 0xE001: + return 0xF001; + case 0xE002: + return 0xF002; + case 0xE0AA: + return 0xF003; + case 0xE005: + return 0xF005; + case 0xE006: + return 0xF006; + case 0xE007: + return 0xF007; + case 0xE071: + return 0xF008; + case 0xE072: + return 0xF009; + case 0xE07F: + return 0xF00A; + case 0xE0E1: + return 0xF00B; + case 0xE0EE: + return 0xF00C; + case 0xE0F1: + return 0xF00D; + case 0xE0FE: + return 0xF00E; + case 0xE0EF: + return 0xF00F; + + default: + return scan_code; + } +} + +void get_registry_key_map() +{ + char *keyName = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout"; + char *valueName = "Scancode Map"; + char buf[32768]; + DWORD bufSize; + HKEY hKey; + int j; + + /* First, prepare the default scan code map list which is 1:1. + Remappings will be inserted directly into it. + 65536 bytes so scan codes fit in easily and it's easy to find what each maps too, + since each array element is a scan code and provides for E0, etc. ones too. */ + for (j = 0; j < 65536; j++) + scancode_map[j] = convert_scan_code(j); + + bufSize = 32768; + /* Get the scan code remappings from: + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */ + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) + { + if(RegQueryValueEx(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS) + { + UINT32 *bufEx2 = (UINT32 *) buf; + int scMapCount = bufEx2[2]; + if ((bufSize != 0) && (scMapCount != 0)) + { + UINT16 *bufEx = (UINT16 *) (buf + 12); + for (j = 0; j < scMapCount*2; j += 2) + { + /* Each scan code is 32-bit: 16 bits of remapped scan code, + and 16 bits of original scan code. */ + int scancode_unmapped = bufEx[j + 1]; + int scancode_mapped = bufEx[j]; + + scancode_mapped = convert_scan_code(scancode_mapped); + + /* Fixes scan code map logging. */ + scancode_map[scancode_unmapped] = scancode_mapped; + } + } + } + RegCloseKey(hKey); + } +} + +static char **argv; +static int argc; +static char *argbuf; + +static void process_command_line() +{ + char *cmdline; + int argc_max; + int i, q; + + cmdline = GetCommandLine(); + i = strlen(cmdline) + 1; + argbuf = malloc(i); + memcpy(argbuf, cmdline, i); + + argc = 0; + argc_max = 64; + argv = malloc(sizeof(char *) * argc_max); + if (!argv) + { + free(argbuf); + return; + } + + i = 0; + + /* parse commandline into argc/argv format */ + while (argbuf[i]) + { + while (argbuf[i] == ' ') + i++; + + if (argbuf[i]) + { + if ((argbuf[i] == '\'') || (argbuf[i] == '"')) + { + q = argbuf[i++]; + if (!argbuf[i]) + break; + } + else + q = 0; + + argv[argc++] = &argbuf[i]; + + if (argc >= argc_max) + { + argc_max += 64; + argv = realloc(argv, sizeof(char *) * argc_max); + if (!argv) + { + free(argbuf); + return; + } + } + + while ((argbuf[i]) && ((q) ? (argbuf[i] != q) : (argbuf[i] != ' '))) + i++; + + if (argbuf[i]) + { + argbuf[i] = 0; + i++; + } + // pclog("Arg %i - %s\n",argc-1,argv[argc-1]); + } + } + + argv[argc] = NULL; +} + +int WINAPI WinMain (HINSTANCE hThisInstance, + HINSTANCE hPrevInstance, + LPSTR lpszArgument, + int nFunsterStil) + +{ + HWND hwnd; /* This is the handle for our window */ + MSG messages; /* Here messages to the application are saved */ + WNDCLASSEX wincl; /* Data structure for the windowclass */ + int c, d; + LARGE_INTEGER qpc_freq; + + process_command_line(); + + hinstance=hThisInstance; + /* The Window structure */ + wincl.hInstance = hThisInstance; + wincl.lpszClassName = szClassName; + wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ + wincl.style = CS_DBLCLKS; /* Catch double-clicks */ + wincl.cbSize = sizeof (WNDCLASSEX); + + /* Use default icon and mouse-pointer */ + wincl.hIcon = LoadIcon (hinstance, 100); + wincl.hIconSm = LoadIcon (hinstance, 100); + wincl.hCursor = NULL;//LoadCursor (NULL, IDC_ARROW); + wincl.lpszMenuName = NULL; /* No menu */ + wincl.cbClsExtra = 0; /* No extra bytes after the window class */ + wincl.cbWndExtra = 0; /* structure or the window instance */ + /* Use Windows's default color as the background of the window */ + wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; + + /* Register the window class, and if it fails quit the program */ + if (!RegisterClassEx(&wincl)) + return 0; + + wincl.lpszClassName = szSubClassName; + wincl.lpfnWndProc = subWindowProcedure; /* This function is called by windows */ + + if (!RegisterClassEx(&wincl)) + return 0; + + menu = LoadMenu(hThisInstance, TEXT("MainMenu")); + initmenu(); + + /* The class is registered, let's create the program*/ + hwnd = CreateWindowEx ( + 0, /* Extended possibilites for variation */ + szClassName, /* Classname */ + "PCem v11 [Experimental]", /* Title Text */ + WS_OVERLAPPEDWINDOW&~WS_SIZEBOX, /* default window */ + CW_USEDEFAULT, /* Windows decides the position */ + CW_USEDEFAULT, /* where the window ends up on the screen */ + 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */ + 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ + HWND_DESKTOP, /* The window is a child-window to desktop */ + menu, /* Menu */ + hThisInstance, /* Program Instance handler */ + NULL /* No Window Creation data */ + ); + + /* Make the window visible on the screen */ + ShowWindow (hwnd, nFunsterStil); + +// win_set_window(hwnd); + + memset(rawinputkey, 0, sizeof(rawinputkey)); + device.usUsagePage = 0x01; + device.usUsage = 0x06; + device.dwFlags = RIDEV_NOHOTKEYS; + device.hwndTarget = hwnd; + + if (RegisterRawInputDevices(&device, 1, sizeof(device))) + pclog("Raw input registered!\n"); + else + pclog("Raw input registration failed!\n"); + + get_registry_key_map(); + + ghwnd=hwnd; + + initpc(argc, argv); + + // pclog("Setting video API...\n"); + vid_apis[0][vid_api].init(ghwnd); + + // pclog("Resizing window...\n"); + if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); + else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); + + // pclog("Checking CD-ROM menu item...\n"); + if (!cdrom_enabled) + CheckMenuItem(menu, IDM_CDROM_DISABLED, MF_CHECKED); + else + { + if (cdrom_drive == 200) + CheckMenuItem(menu, IDM_CDROM_ISO, MF_CHECKED); + else + CheckMenuItem(menu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); + } + // pclog("Checking video resize menu item...\n"); + if (vid_resize) CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED); + // pclog("Checking video API menu item...\n"); + CheckMenuItem(menu, IDM_VID_DDRAW + vid_api, MF_CHECKED); + // pclog("Checking video fill screen menu item...\n"); + CheckMenuItem(menu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); + CheckMenuItem(menu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); +// set_display_switch_mode(SWITCH_BACKGROUND); + + // pclog("Preparing ROM sets...\n"); + d=romset; + for (c=0;c= 0; c--) + { + if (gfx_present[c]) + { + gfxcard = c; + saveconfig(); + resetpchard(); + break; + } + } + } + + loadbios(); + resetpchard(); + + timeBeginPeriod(1); + + atexit(releasemouse); + +// QueryPerformanceFrequency(&counter_base); +/// QueryPerformanceCounter(&counter_posold); +// counter_posold.QuadPart*=100; + + InitializeCriticalSection(&cs); + mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL); + SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST); + + + updatewindowsize(640, 480); + + QueryPerformanceFrequency(&qpc_freq); + timer_freq = qpc_freq.QuadPart; + +// focus=1; +// setrefresh(100); + +// ShowCursor(TRUE); + + if (start_in_fullscreen) + { + startblit(); + mouse_close(); + vid_apis[0][vid_api].close(); + video_fullscreen = 1; + vid_apis[1][vid_api].init(ghwnd); + mouse_init(); + leave_fullscreen_flag = 0; + endblit(); + device_force_redraw(); + } + if (window_remember) + { + MoveWindow(hwnd, window_x, window_y, + window_w, + window_h, + TRUE); + } + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (!quited) + { +/* if (infocus) + { + if (drawits) + { + drawits--; + if (drawits>10) drawits=0; + runpc(); + } +//; else +// sleep(0); + // if ((pcem_key[KEY_LCONTROL] || pcem_key[KEY_RCONTROL]) && pcem_key[KEY_END] && mousecapture) + // if ((pcem_key[KEY_LCONTROL] || pcem_key[KEY_RCONTROL]) && pcem_key[0x58] && mousecapture) + // if (pcem_key[0x58] && pcem_key[0x42] && mousecapture) + { + ClipCursor(&oldclip); + mousecapture=0; + } + }*/ + + while (GetMessage(&messages,NULL,0,0) && !quited) + { + if (messages.message==WM_QUIT) quited=1; + TranslateMessage(&messages); + DispatchMessage(&messages); + // if ((pcem_key[KEY_LCONTROL] || pcem_key[KEY_RCONTROL]) && pcem_key[KEY_END] && mousecapture) + if (pcem_key[0x58] && pcem_key[0x42] && mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } + + if (pcem_key[0x58] && pcem_key[0x41]) + { + // pclog("Taking screenshot...\n"); + take_screenshot(); + } + + if (pcem_key[0x58] && pcem_key[0x44]) + { + pause=1; + Sleep(100); + resetpc_cad(); + pause=0; + } + + if (pcem_key[0x58] && pcem_key[0x43]) + { + pause=1; + Sleep(100); + resetpchard(); + pause=0; + } + +#ifndef RELEASE_BUILD + if (pcem_key[0x57] && pcem_key[0x58]) + { + pclog("Log breakpoint\n"); + } +#endif + + if ((pcem_key[0x1D] || pcem_key[0x9D]) && + (pcem_key[0x38] || pcem_key[0xB8]) && + (pcem_key[0x51] || pcem_key[0xD1]) && + video_fullscreen) + { + leave_fullscreen(); + } + } + + quited=1; +// else +// sleep(10); + } + + startblit(); +// pclog("Sleep 1000\n"); + Sleep(200); +// pclog("TerminateThread\n"); + TerminateThread(mainthreadh,0); +// pclog("Quited? %i\n",quited); +// pclog("Closepc\n"); + if (save_window_pos && window_remember) + saveconfig(); + closepc(); +// pclog("dumpregs\n"); + + vid_apis[video_fullscreen][vid_api].close(); + + timeEndPeriod(1); +// dumpregs(); + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + } + + UnregisterClass(szSubClassName, hinstance); + UnregisterClass(szClassName, hinstance); + +// pclog("Ending! %i %i\n",messages.wParam,quited); + return messages.wParam; +} + +char openfilestring[260]; +int getfile(HWND hwnd, char *f, char *fn) +{ + OPENFILENAME ofn; // common dialog box structure + BOOL r; + DWORD err; + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = openfilestring; + // + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + // +// ofn.lpstrFile[0] = '\0'; + strcpy(ofn.lpstrFile,fn); + ofn.nMaxFile = sizeof(openfilestring); + ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // Display the Open dialog box. + + pclog("GetOpenFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetOpenFileName(&ofn); + if (r) + { + pclog("GetOpenFileName return true\n"); + return 0; + } + pclog("GetOpenFileName return false\n"); + err = CommDlgExtendedError(); + pclog("CommDlgExtendedError return %04X\n", err); + return 1; +} + +int getsfile(HWND hwnd, char *f, char *fn) +{ + OPENFILENAME ofn; // common dialog box structure + BOOL r; + DWORD err; + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = openfilestring; + // + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + // +// ofn.lpstrFile[0] = '\0'; + strcpy(ofn.lpstrFile,fn); + ofn.nMaxFile = sizeof(openfilestring); + ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // Display the Open dialog box. + + pclog("GetSaveFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetSaveFileName(&ofn); + if (r) + { + pclog("GetSaveFileName return true\n"); + return 0; + } + pclog("GetSaveFileName return false\n"); + err = CommDlgExtendedError(); + pclog("CommDlgExtendedError return %04X\n", err); + return 1; +} + + + + +HHOOK hKeyboardHook; + +LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) +{ + if (nCode < 0 || nCode != HC_ACTION || (!mousecapture && !video_fullscreen)) + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam); + + KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam; + + if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab + if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab + if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1;//disable windows keys + if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1;//disable alt-escape + BOOL bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);//checks ctrl key pressed + if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; //disable ctrl-escape + + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); +} + +void atapi_close(void) +{ + switch (cdrom_drive) + { + case 0: + null_close(); + break; + default: + ioctl_close(); + break; + case 200: + iso_close(); + break; + } +} + +LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HMENU hmenu; + RECT rect; + uint32_t ri_size = 0; + char temp_iso_path[1024]; + int new_cdrom_drive; +// pclog("Message %i %08X\n",message,message); + switch (message) + { + case WM_CREATE: + SetTimer(hwnd, TIMER_1SEC, 1000, NULL); + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); + break; + + case WM_COMMAND: +// pclog("WM_COMMAND %i\n",LOWORD(wParam)); + hmenu=GetMenu(hwnd); + switch (LOWORD(wParam)) + { +#if 0 + case IDM_FILE_RESET: + pause=1; + Sleep(100); + resetpc(); + pause=0; + break; +#endif + case IDM_FILE_HRESET: + pause=1; + Sleep(100); + resetpchard(); + pause=0; + break; + case IDM_FILE_RESET_CAD: + pause=1; + Sleep(100); + resetpc_cad(); + pause=0; + break; + case IDM_FILE_EXIT: + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + case IDM_DISC_A: + if (!getfile(hwnd,"Disc image (*.IMG;*.IMA;*.FDI)\0*.IMG;*.IMA;*.FDI\0All files (*.*)\0*.*\0",discfns[0])) + { + disc_close(0); + disc_load(0, openfilestring); + saveconfig(); + } + break; + case IDM_DISC_B: + if (!getfile(hwnd,"Disc image (*.IMG;*.IMA;*.FDI)\0*.IMG;*.IMA;*.FDI\0All files (*.*)\0*.*\0",discfns[1])) + { + disc_close(1); + disc_load(1, openfilestring); + saveconfig(); + } + break; + case IDM_EJECT_A: + disc_close(0); + saveconfig(); + break; + case IDM_EJECT_B: + disc_close(1); + saveconfig(); + break; + case IDM_HDCONF: + hdconf_open(hwnd); + break; + case IDM_CONFIG: + config_open(hwnd); + break; + case IDM_STATUS: + status_open(hwnd); + break; + + case IDM_VID_RESIZE: + vid_resize=!vid_resize; + CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)?MF_CHECKED:MF_UNCHECKED); + if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); + else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); + GetWindowRect(hwnd,&rect); + SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); + saveconfig(); + break; + case IDM_VID_REMEMBER: + window_remember = !window_remember; + CheckMenuItem(hmenu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); + GetWindowRect(hwnd, &rect); + if (window_remember) + { + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + } + saveconfig(); + break; + + case IDM_VID_DDRAW: case IDM_VID_D3D: + startblit(); + CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_UNCHECKED); + vid_apis[0][vid_api].close(); + vid_api = LOWORD(wParam) - IDM_VID_DDRAW; + CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_CHECKED); + vid_apis[0][vid_api].init(ghwnd); + endblit(); + saveconfig(); + device_force_redraw(); + break; + + case IDM_VID_FULLSCREEN: + if (video_fullscreen_first) + { + video_fullscreen_first = 0; + MessageBox(hwnd, "Use CTRL + ALT + PAGE DOWN to return to windowed mode", "PCem", MB_OK); + } + startblit(); + mouse_close(); + vid_apis[0][vid_api].close(); + video_fullscreen = 1; + vid_apis[1][vid_api].init(ghwnd); + mouse_init(); + leave_fullscreen_flag = 0; + endblit(); + device_force_redraw(); + break; + + case IDM_VID_FS_FULL: + case IDM_VID_FS_43: + case IDM_VID_FS_SQ: + case IDM_VID_FS_INT: + CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_UNCHECKED); + video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; + CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); + saveconfig(); + break; + + case IDM_CONFIG_LOAD: + pause = 1; + if (!getfile(hwnd, "Configuration (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0", "")) + { + if (MessageBox(NULL, "This will reset PCem!\nOkay to continue?", "PCem", MB_OKCANCEL) == IDOK) + { + loadconfig(openfilestring); + config_save(config_file_default); + mem_resize(); + loadbios(); + resetpchard(); + } + } + pause = 0; + break; + + case IDM_CONFIG_SAVE: + pause = 1; + if (!getsfile(hwnd, "Configuration (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0", "")) + config_save(openfilestring); + pause = 0; + break; + + case IDM_CDROM_DISABLED: + if (cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + if (!cdrom_enabled) + { + /* Switching from disabled to disabled. Do nothing. */ + break; + } + atapi->exit(); + atapi_close(); + cdrom_null_open(0); + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_CHECKED); + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); + old_cdrom_drive = cdrom_drive; + cdrom_drive=0; + CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_UNCHECKED); + if (cdrom_enabled) + { + pause = 1; + Sleep(100); + cdrom_enabled = 0; + saveconfig(); + resetpchard(); + pause = 0; + } + break; + + case IDM_CDROM_EMPTY: + if (!cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + if ((cdrom_drive == 0) && cdrom_enabled) + { + /* Switch from empty to empty. Do nothing. */ + break; + } + atapi->exit(); + atapi_close(); + cdrom_null_open(0); + if (cdrom_enabled) + { + /* Signal disc change to the emulated machine. */ + atapi_insert_cdrom(); + } + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); + old_cdrom_drive = cdrom_drive; + cdrom_drive=0; + CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_CHECKED); + saveconfig(); + if (!cdrom_enabled) + { + pause = 1; + Sleep(100); + cdrom_enabled = 1; + saveconfig(); + resetpchard(); + pause = 0; + } + break; + + case IDM_CDROM_ISO: + if (!getfile(hwnd,"CD-ROM image (*.ISO)\0*.ISO\0All files (*.*)\0*.*\0",iso_path)) + { + if (!cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + old_cdrom_drive = cdrom_drive; + strcpy(temp_iso_path, openfilestring); + if ((strcmp(iso_path, temp_iso_path) == 0) && (cdrom_drive == 200) && cdrom_enabled) + { + /* Switching from ISO to the same ISO. Do nothing. */ + break; + } + atapi->exit(); + atapi_close(); + iso_open(temp_iso_path); + if (cdrom_enabled) + { + /* Signal disc change to the emulated machine. */ + atapi_insert_cdrom(); + } + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); + cdrom_drive = 200; + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_CHECKED); + saveconfig(); + if (!cdrom_enabled) + { + pause = 1; + Sleep(100); + cdrom_enabled = 1; + saveconfig(); + resetpchard(); + pause = 0; + } + } + break; + + default: + if (LOWORD(wParam)>IDM_CDROM_REAL && LOWORD(wParam)<(IDM_CDROM_REAL+100)) + { + if (!cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + new_cdrom_drive = LOWORD(wParam)-IDM_CDROM_REAL; + if ((cdrom_drive == new_cdrom_drive) && cdrom_enabled) + { + /* Switching to the same drive. Do nothing. */ + break; + } + old_cdrom_drive = cdrom_drive; + atapi->exit(); + atapi_close(); + ioctl_open(new_cdrom_drive); + if (cdrom_enabled) + { + /* Signal disc change to the emulated machine. */ + atapi_insert_cdrom(); + } + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); + cdrom_drive = new_cdrom_drive; + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); + saveconfig(); + if (!cdrom_enabled) + { + pause = 1; + Sleep(100); + cdrom_enabled = 1; + saveconfig(); + resetpchard(); + pause = 0; + } + } + break; + } + return 0; + + case WM_INPUT: + { + UINT size; + RAWINPUT *raw; + + if (!infocus) + break; + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + + raw = malloc(size); + + if (raw == NULL) + { + return 0; + } + + /* Here we read the raw input data for the keyboard */ + ri_size = GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); + + if(ri_size != size) + { + return 0; + } + + /* If the input is keyboard, we process it */ + if (raw->header.dwType == RIM_TYPEKEYBOARD) + { + const RAWKEYBOARD rawKB = raw->data.keyboard; + USHORT scancode = rawKB.MakeCode; + + // pclog("Keyboard input received: S:%X VK:%X F:%X\n", c, d, e); + + /* If it's not a scan code that starts with 0xE1 */ + if (!(rawKB.Flags & RI_KEY_E1)) + { + // pclog("Non-E1 triggered, make code is %04X\n", rawKB.MakeCode); + if (rawKB.Flags & RI_KEY_E0) + scancode |= (0xE0 << 8); + + /* Remap it according to the list from the Registry */ + scancode = scancode_map[scancode]; + + if ((scancode >> 8) == 0xF0) + scancode |= 0x100; /* Extended key code in disambiguated format */ + else if ((scancode >> 8) == 0xE0) + scancode |= 0x80; /* Normal extended key code */ + + /* If it's not 0 (therefore not 0xE1, 0xE2, etc), + then pass it on to the rawinputkey array */ + if (!(scancode & 0xf00)) + { + rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); + pcem_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; + } + } + else + { + // pclog("E1 triggered, make code is %04X\n", rawKB.MakeCode); + if (rawKB.MakeCode == 0x1D) + scancode = 0xFF; + if (!(scancode & 0xf00)) + { + rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); + pcem_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; + } + } + } + free(raw); + + } + break; + + case WM_SETFOCUS: + infocus=1; + // QueryPerformanceCounter(&counter_posold); +// pclog("Set focus!\n"); + break; + case WM_KILLFOCUS: + infocus=0; + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } +// pclog("Lost focus!\n"); + memset(rawinputkey, 0, sizeof(rawinputkey)); + if (video_fullscreen) + leave_fullscreen_flag = 1; + break; + + case WM_LBUTTONUP: + if (!mousecapture && !video_fullscreen) + { + RECT pcclip; + + GetClipCursor(&oldclip); + GetWindowRect(hwnd, &pcclip); + pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; + pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + ClipCursor(&pcclip); + mousecapture = 1; +// ShowCursor(FALSE); + while (1) + { + if (ShowCursor(FALSE) < 0) break; + } + } + break; + + case WM_MBUTTONUP: + releasemouse(); + break; + + case WM_ENTERMENULOOP: +// if (key[KEY_ALT] || key[KEY_ALTGR]) return 0; + break; + + case WM_SIZE: + winsizex=lParam&0xFFFF; + winsizey=lParam>>16; + + if (vid_apis[video_fullscreen][vid_api].resize) + { + startblit(); + vid_apis[video_fullscreen][vid_api].resize(winsizex, winsizey); + endblit(); + } + + if (mousecapture) + { + RECT pcclip; + + GetWindowRect(hwnd, &pcclip); + pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; + pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + ClipCursor(&pcclip); + } + if (window_remember) + { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + break; + + case WM_MOVE: + if (window_remember) + { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + break; + + case WM_TIMER: + if (wParam == TIMER_1SEC) + onesec(); + break; + + case WM_RESETD3D: + startblit(); + if (video_fullscreen) + d3d_fs_reset(); + else + d3d_reset(); + endblit(); + break; + + case WM_LEAVEFULLSCREEN: + startblit(); + mouse_close(); + vid_apis[1][vid_api].close(); + video_fullscreen = 0; + vid_apis[0][vid_api].init(ghwnd); + mouse_init(); + endblit(); + device_force_redraw(); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: +// if (mousecapture) + return 0; +// return DefWindowProc (hwnd, message, wParam, lParam); + + + case WM_DESTROY: + UnhookWindowsHookEx( hKeyboardHook ); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + + case WM_SYSCOMMAND: + if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0 && (video_fullscreen || mousecapture)) + return 0; /*disable ALT key for menu*/ + + default: +// pclog("Def %08X %i\n",message,message); + return DefWindowProc (hwnd, message, wParam, lParam); + } + return 0; +} + +LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + return 0; +} diff --git a/src/win.h b/src/win.h new file mode 100644 index 000000000..4aff67266 --- /dev/null +++ b/src/win.h @@ -0,0 +1,35 @@ +extern HINSTANCE hinstance; +extern HWND ghwnd; +extern int mousecapture; + +#ifdef __cplusplus +extern "C" { +#endif + +#define szClassName "PCemMainWnd" +#define szSubClassName "PCemSubWnd" + +void leave_fullscreen(); + +#ifdef __cplusplus +} +#endif + + +void status_open(HWND hwnd); +extern HWND status_hwnd; +extern int status_is_open; + +void hdconf_open(HWND hwnd); + +void config_open(HWND hwnd); + +void deviceconfig_open(HWND hwnd, struct device_t *device); +void joystickconfig_open(HWND hwnd, int joy_nr, int type); + +extern char openfilestring[260]; + +int getfile(HWND hwnd, char *f, char *fn); +int getsfile(HWND hwnd, char *f, char *fn); + +extern int pause; diff --git a/src/x86.h b/src/x86.h new file mode 100644 index 000000000..ecd929faf --- /dev/null +++ b/src/x86.h @@ -0,0 +1,108 @@ +uint16_t oldcs; +uint32_t oldpc; +extern uint32_t rmdat32; +int oldcpl; + +extern int nmi_enable; + +int tempc; +int cycles,output; +int ssegs; +int firstrepcycle; + +uint32_t easeg,eaaddr,ealimit,ealimitw; +int rm,reg,mod,rmdat; + +int skipnextprint; +int inhlt; + +uint8_t opcode; +int ins,noint; + +uint16_t lastcs,lastpc; +int timetolive,keyboardtimer; + +#define setznp168 setznp16 + +#define getr8(r) ((r&4)?cpu_state.regs[r&3].b.h:cpu_state.regs[r&3].b.l) +#define getr16(r) cpu_state.regs[r].w +#define getr32(r) cpu_state.regs[r].l + +#define setr8(r,v) if (r&4) cpu_state.regs[r&3].b.h=v; \ + else cpu_state.regs[r&3].b.l=v; +#define setr16(r,v) cpu_state.regs[r].w=v +#define setr32(r,v) cpu_state.regs[r].l=v + +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +int use32; +int stack32; + +#define fetchea() { rmdat=readmemb(cs+pc); pc++; \ + reg=(rmdat>>3)&7; \ + mod=(rmdat>>6)&3; \ + rm=rmdat&7; \ + if (mod!=3) fetcheal(); } + + +int optype; +#define JMP 1 +#define CALL 2 +#define IRET 3 +#define OPTYPE_INT 4 + +uint32_t oxpc; + +extern uint16_t *mod1add[2][8]; +extern uint32_t *mod1seg[8]; + + +#define IRQTEST ((flags&I_FLAG) && (pic.pend&~pic.mask) && !noint) + +extern int cgate32; + + +extern uint32_t *eal_r, *eal_w; + + +extern uint32_t flags_zn; +extern uint8_t flags_p; +#define FLAG_N (flags_zn>>31) +#define FLAG_Z (flags_zn) +#define FLAG_P (znptable8[flags_p]&P_FLAG) + +extern int gpf; + + +enum +{ + ABRT_NONE = 0, + ABRT_GEN, + ABRT_TS = 0xA, + ABRT_NP = 0xB, + ABRT_SS = 0xC, + ABRT_GPF = 0xD, + ABRT_PF = 0xE +}; + +extern int abrt; +extern uint32_t abrt_error; + +void x86_doabrt(int x86_abrt); + +extern uint8_t opcode2; + +extern uint16_t rds; +extern uint32_t rmdat32; + +extern int inscounts[256]; + +void x86illegal(); + +void x86seg_reset(); +void x86gpf(char *s, uint16_t error); + +extern uint16_t zero; + +extern int x86_was_reset; diff --git a/src/x86_flags.h b/src/x86_flags.h new file mode 100644 index 000000000..d663fd464 --- /dev/null +++ b/src/x86_flags.h @@ -0,0 +1,507 @@ +enum +{ + FLAGS_UNKNOWN, + + FLAGS_ZN8, + FLAGS_ZN16, + FLAGS_ZN32, + + FLAGS_ADD8, + FLAGS_ADD16, + FLAGS_ADD32, + + FLAGS_SUB8, + FLAGS_SUB16, + FLAGS_SUB32, + + FLAGS_SHL8, + FLAGS_SHL16, + FLAGS_SHL32, + + FLAGS_SHR8, + FLAGS_SHR16, + FLAGS_SHR32, + + FLAGS_SAR8, + FLAGS_SAR16, + FLAGS_SAR32, + + FLAGS_INC8, + FLAGS_INC16, + FLAGS_INC32, + + FLAGS_DEC8, + FLAGS_DEC16, + FLAGS_DEC32, +}; + +static inline int ZF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return !cpu_state.flags_res; + + case FLAGS_UNKNOWN: + return flags & Z_FLAG; + } +} + +static inline int NF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + return cpu_state.flags_res & 0x80; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + return cpu_state.flags_res & 0x8000; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + return cpu_state.flags_res & 0x80000000; + + case FLAGS_UNKNOWN: + return flags & N_FLAG; + } +} + +static inline int PF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; + + case FLAGS_UNKNOWN: + return flags & P_FLAG; + } +} + +static inline int VF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_INC8: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_ADD16: + case FLAGS_INC16: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_ADD32: + case FLAGS_INC32: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SUB8: + case FLAGS_DEC8: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_SUB16: + case FLAGS_DEC16: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_SUB32: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SHL8: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80); + case FLAGS_SHL16: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x8000); + case FLAGS_SHL32: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80000000); + + case FLAGS_SHR8: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80)); + case FLAGS_SHR16: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x8000)); + case FLAGS_SHR32: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); + + case FLAGS_UNKNOWN: + return flags & V_FLAG; + } +} + +static inline int AF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_UNKNOWN: + return flags & A_FLAG; + } +} + +static inline int CF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ADD8: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100; + case FLAGS_ADD16: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000; + case FLAGS_ADD32: + return (cpu_state.flags_res < cpu_state.flags_op1); + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + return (cpu_state.flags_op1 < cpu_state.flags_op2); + + case FLAGS_SHL8: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80; + case FLAGS_SHL16: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000; + case FLAGS_SHL32: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000; + + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + return (cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_SAR8: + return ((int8_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR16: + return ((int16_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR32: + return ((int32_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + return 0; + + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_UNKNOWN: + return flags & C_FLAG; + } +} + +//#define ZF_SET() (flags & Z_FLAG) +//#define NF_SET() (flags & N_FLAG) +//#define PF_SET() (flags & P_FLAG) +//#define VF_SET() (flags & V_FLAG) +//#define CF_SET() (flags & C_FLAG) +//#define AF_SET() (flags & A_FLAG) + +static inline void flags_rebuild() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + uint16_t tempf = 0; + if (CF_SET()) tempf |= C_FLAG; + if (PF_SET()) tempf |= P_FLAG; + if (AF_SET()) tempf |= A_FLAG; + if (ZF_SET()) tempf |= Z_FLAG; + if (NF_SET()) tempf |= N_FLAG; + if (VF_SET()) tempf |= V_FLAG; + flags = (flags & ~0x8d5) | tempf; + cpu_state.flags_op = FLAGS_UNKNOWN; + } +} + +static inline void flags_extract() +{ + cpu_state.flags_op = FLAGS_UNKNOWN; +} + +static inline void flags_rebuild_c() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + if (CF_SET()) + flags |= C_FLAG; + else + flags &= ~C_FLAG; + } +} + +static inline void setznp8(uint8_t val) +{ + cpu_state.flags_op = FLAGS_ZN8; + cpu_state.flags_res = val; +} +static inline void setznp16(uint16_t val) +{ + cpu_state.flags_op = FLAGS_ZN16; + cpu_state.flags_res = val; +} +static inline void setznp32(uint32_t val) +{ + cpu_state.flags_op = FLAGS_ZN32; + cpu_state.flags_res = val; +} + +#define set_flags_shift(op, orig, shift, res) \ + cpu_state.flags_op = op; \ + cpu_state.flags_res = res; \ + cpu_state.flags_op1 = orig; \ + cpu_state.flags_op2 = shift; + +static inline void setadd8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_ADD8; +} +static inline void setadd16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_ADD16; +} +static inline void setadd32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_ADD32; +} +static inline void setadd8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_INC8; +} +static inline void setadd16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_INC16; +} +static inline void setadd32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_INC32; +} + +static inline void setsub8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_SUB8; +} +static inline void setsub16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_SUB16; +} +static inline void setsub32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_SUB32; +} + +static inline void setsub8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_DEC8; +} +static inline void setsub16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_DEC16; +} +static inline void setsub32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_DEC32; +} + +static inline void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static inline void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} + +static inline void setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static inline void setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} + +static inline void setadc32(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + flags|=(znptable8[c&0xFF]&P_FLAG); + if ((ca) || (c==a && tempc)) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) flags|=V_FLAG; + if (((a&0xF)-((b&0xF)+tempc))&0x10) flags|=A_FLAG; +} + diff --git a/src/x86_ops.h b/src/x86_ops.h new file mode 100644 index 000000000..279f62bbf --- /dev/null +++ b/src/x86_ops.h @@ -0,0 +1,138 @@ +#ifndef _X86_OPS_H +#define _X86_OPS_H + +typedef int (*OpFn)(uint32_t fetchdat); + +void x86_setopcodes(OpFn *opcodes, OpFn *opcodes_0f, OpFn *dynarec_opcodes, OpFn *dynarec_opcodes_0f); + +extern OpFn *x86_dynarec_opcodes; +extern OpFn *x86_dynarec_opcodes_0f; +extern OpFn *x86_dynarec_opcodes_d8_a16; +extern OpFn *x86_dynarec_opcodes_d8_a32; +extern OpFn *x86_dynarec_opcodes_d9_a16; +extern OpFn *x86_dynarec_opcodes_d9_a32; +extern OpFn *x86_dynarec_opcodes_da_a16; +extern OpFn *x86_dynarec_opcodes_da_a32; +extern OpFn *x86_dynarec_opcodes_db_a16; +extern OpFn *x86_dynarec_opcodes_db_a32; +extern OpFn *x86_dynarec_opcodes_dc_a16; +extern OpFn *x86_dynarec_opcodes_dc_a32; +extern OpFn *x86_dynarec_opcodes_dd_a16; +extern OpFn *x86_dynarec_opcodes_dd_a32; +extern OpFn *x86_dynarec_opcodes_de_a16; +extern OpFn *x86_dynarec_opcodes_de_a32; +extern OpFn *x86_dynarec_opcodes_df_a16; +extern OpFn *x86_dynarec_opcodes_df_a32; + +extern OpFn dynarec_ops_286[1024]; +extern OpFn dynarec_ops_286_0f[1024]; + +extern OpFn dynarec_ops_386[1024]; +extern OpFn dynarec_ops_386_0f[1024]; + +extern OpFn dynarec_ops_486_0f[1024]; + +extern OpFn dynarec_ops_winchip_0f[1024]; + +extern OpFn dynarec_ops_pentium_0f[1024]; +extern OpFn dynarec_ops_pentiummmx_0f[1024]; + +extern OpFn dynarec_ops_k6_0f[1024]; + +extern OpFn dynarec_ops_c6x86mx_0f[1024]; +extern OpFn dynarec_ops_pentiumpro_0f[1024]; +extern OpFn dynarec_ops_pentium2_0f[1024]; +extern OpFn dynarec_ops_pentium2d_0f[1024]; + +extern OpFn dynarec_ops_fpu_d8_a16[32]; +extern OpFn dynarec_ops_fpu_d8_a32[32]; +extern OpFn dynarec_ops_fpu_d9_a16[256]; +extern OpFn dynarec_ops_fpu_d9_a32[256]; +extern OpFn dynarec_ops_fpu_da_a16[256]; +extern OpFn dynarec_ops_fpu_da_a32[256]; +extern OpFn dynarec_ops_fpu_db_a16[256]; +extern OpFn dynarec_ops_fpu_db_a32[256]; +extern OpFn dynarec_ops_fpu_dc_a16[32]; +extern OpFn dynarec_ops_fpu_dc_a32[32]; +extern OpFn dynarec_ops_fpu_dd_a16[256]; +extern OpFn dynarec_ops_fpu_dd_a32[256]; +extern OpFn dynarec_ops_fpu_de_a16[256]; +extern OpFn dynarec_ops_fpu_de_a32[256]; +extern OpFn dynarec_ops_fpu_df_a16[256]; +extern OpFn dynarec_ops_fpu_df_a32[256]; +extern OpFn dynarec_ops_nofpu_a16[256]; +extern OpFn dynarec_ops_nofpu_a32[256]; + +extern OpFn dynarec_ops_fpu_686_da_a16[256]; +extern OpFn dynarec_ops_fpu_686_da_a32[256]; +extern OpFn dynarec_ops_fpu_686_db_a16[256]; +extern OpFn dynarec_ops_fpu_686_db_a32[256]; +extern OpFn dynarec_ops_fpu_686_df_a16[256]; +extern OpFn dynarec_ops_fpu_686_df_a32[256]; + +extern OpFn *x86_opcodes; +extern OpFn *x86_opcodes_0f; +extern OpFn *x86_opcodes_d8_a16; +extern OpFn *x86_opcodes_d8_a32; +extern OpFn *x86_opcodes_d9_a16; +extern OpFn *x86_opcodes_d9_a32; +extern OpFn *x86_opcodes_da_a16; +extern OpFn *x86_opcodes_da_a32; +extern OpFn *x86_opcodes_db_a16; +extern OpFn *x86_opcodes_db_a32; +extern OpFn *x86_opcodes_dc_a16; +extern OpFn *x86_opcodes_dc_a32; +extern OpFn *x86_opcodes_dd_a16; +extern OpFn *x86_opcodes_dd_a32; +extern OpFn *x86_opcodes_de_a16; +extern OpFn *x86_opcodes_de_a32; +extern OpFn *x86_opcodes_df_a16; +extern OpFn *x86_opcodes_df_a32; + +extern OpFn ops_286[1024]; +extern OpFn ops_286_0f[1024]; + +extern OpFn ops_386[1024]; +extern OpFn ops_386_0f[1024]; + +extern OpFn ops_486_0f[1024]; + +extern OpFn ops_winchip_0f[1024]; + +extern OpFn ops_pentium_0f[1024]; +extern OpFn ops_pentiummmx_0f[1024]; + +extern OpFn ops_k6_0f[1024]; + +extern OpFn ops_c6x86mx_0f[1024]; +extern OpFn ops_pentiumpro_0f[1024]; +extern OpFn ops_pentium2_0f[1024]; +extern OpFn ops_pentium2d_0f[1024]; + +extern OpFn ops_fpu_d8_a16[32]; +extern OpFn ops_fpu_d8_a32[32]; +extern OpFn ops_fpu_d9_a16[256]; +extern OpFn ops_fpu_d9_a32[256]; +extern OpFn ops_fpu_da_a16[256]; +extern OpFn ops_fpu_da_a32[256]; +extern OpFn ops_fpu_db_a16[256]; +extern OpFn ops_fpu_db_a32[256]; +extern OpFn ops_fpu_dc_a16[32]; +extern OpFn ops_fpu_dc_a32[32]; +extern OpFn ops_fpu_dd_a16[256]; +extern OpFn ops_fpu_dd_a32[256]; +extern OpFn ops_fpu_de_a16[256]; +extern OpFn ops_fpu_de_a32[256]; +extern OpFn ops_fpu_df_a16[256]; +extern OpFn ops_fpu_df_a32[256]; +extern OpFn ops_nofpu_a16[256]; +extern OpFn ops_nofpu_a32[256]; + +extern OpFn ops_fpu_686_da_a16[256]; +extern OpFn ops_fpu_686_da_a32[256]; +extern OpFn ops_fpu_686_db_a16[256]; +extern OpFn ops_fpu_686_db_a32[256]; +extern OpFn ops_fpu_686_df_a16[256]; +extern OpFn ops_fpu_686_df_a32[256]; + +#endif /*_X86_OPS_H*/ diff --git a/src/x86_ops_arith.h b/src/x86_ops_arith.h new file mode 100644 index 000000000..e83638cb6 --- /dev/null +++ b/src/x86_ops_arith.h @@ -0,0 +1,647 @@ +#define OP_ARITH(name, operation, setflags, flagops, gettempc) \ + static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (mod == 3) \ + { \ + uint8_t dst = getr8(rm); \ + uint8_t src = getr8(reg); \ + setflags ## 8 flagops; \ + setr8(rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint8_t dst = geteab(); if (abrt) return 1; \ + uint8_t src = getr8(reg); \ + seteab(operation); if (abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + } \ + return 0; \ + } \ + static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (mod == 3) \ + { \ + uint8_t dst = getr8(rm); \ + uint8_t src = getr8(reg); \ + setflags ## 8 flagops; \ + setr8(rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint8_t dst = geteab(); if (abrt) return 1; \ + uint8_t src = getr8(reg); \ + seteab(operation); if (abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (mod == 3) \ + { \ + uint16_t dst = cpu_state.regs[rm].w; \ + uint16_t src = cpu_state.regs[reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint16_t dst = geteaw(); if (abrt) return 1; \ + uint16_t src = cpu_state.regs[reg].w; \ + seteaw(operation); if (abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + } \ + return 0; \ + } \ + static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (mod == 3) \ + { \ + uint16_t dst = cpu_state.regs[rm].w; \ + uint16_t src = cpu_state.regs[reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint16_t dst = geteaw(); if (abrt) return 1; \ + uint16_t src = cpu_state.regs[reg].w; \ + seteaw(operation); if (abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (mod == 3) \ + { \ + uint32_t dst = cpu_state.regs[rm].l; \ + uint32_t src = cpu_state.regs[reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint32_t dst = geteal(); if (abrt) return 1; \ + uint32_t src = cpu_state.regs[reg].l; \ + seteal(operation); if (abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mrl); \ + } \ + return 0; \ + } \ + static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (mod == 3) \ + { \ + uint32_t dst = cpu_state.regs[rm].l; \ + uint32_t src = cpu_state.regs[reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint32_t dst = geteal(); if (abrt) return 1; \ + uint32_t src = cpu_state.regs[reg].l; \ + seteal(operation); if (abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mrl); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _b_rm_a16(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = getr8(reg); \ + src = geteab(); if (abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(reg, operation); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); \ + return 0; \ + } \ + static int op ## name ## _b_rm_a32(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = getr8(reg); \ + src = geteab(); if (abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(reg, operation); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); \ + return 0; \ + } \ + \ + static int op ## name ## _w_rm_a16(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[reg].w; \ + src = geteaw(); if (abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[reg].w = operation; \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); \ + return 0; \ + } \ + static int op ## name ## _w_rm_a32(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[reg].w; \ + src = geteaw(); if (abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[reg].w = operation; \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); \ + return 0; \ + } \ + \ + static int op ## name ## _l_rm_a16(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[reg].l; \ + src = geteal(); if (abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[reg].l = operation; \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rml); \ + return 0; \ + } \ + static int op ## name ## _l_rm_a32(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[reg].l; \ + src = geteal(); if (abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[reg].l = operation; \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rml); \ + return 0; \ + } \ + \ + static int op ## name ## _AL_imm(uint32_t fetchdat) \ + { \ + uint8_t dst = AL; \ + uint8_t src = getbytef(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 8 flagops; \ + AL = operation; \ + CLOCK_CYCLES(timing_rr); \ + return 0; \ + } \ + \ + static int op ## name ## _AX_imm(uint32_t fetchdat) \ + { \ + uint16_t dst = AX; \ + uint16_t src = getwordf(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 16 flagops; \ + AX = operation; \ + CLOCK_CYCLES(timing_rr); \ + return 0; \ + } \ + \ + static int op ## name ## _EAX_imm(uint32_t fetchdat) \ + { \ + uint32_t dst = EAX; \ + uint32_t src = getlong(); if (abrt) return 1; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 32 flagops; \ + EAX = operation; \ + CLOCK_CYCLES(timing_rr); \ + return 0; \ + } + +OP_ARITH(ADD, dst + src, setadd, (dst, src), 0) +OP_ARITH(ADC, dst + src + tempc, setadc, (dst, src), 1) +OP_ARITH(SUB, dst - src, setsub, (dst, src), 0) +OP_ARITH(SBB, dst - (src + tempc), setsbc, (dst, src), 1) +OP_ARITH(OR, dst | src, setznp, (dst | src), 0) +OP_ARITH(AND, dst & src, setznp, (dst & src), 0) +OP_ARITH(XOR, dst ^ src, setznp, (dst ^ src), 0) + +static int opCMP_b_rmw_a16(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_16(fetchdat); + dst = geteab(); if (abrt) return 1; + setsub8(dst, getr8(reg)); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opCMP_b_rmw_a32(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_32(fetchdat); + dst = geteab(); if (abrt) return 1; + setsub8(dst, getr8(reg)); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opCMP_w_rmw_a16(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_16(fetchdat); + dst = geteaw(); if (abrt) return 1; + setsub16(dst, cpu_state.regs[reg].w); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opCMP_w_rmw_a32(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_32(fetchdat); + dst = geteaw(); if (abrt) return 1; + setsub16(dst, cpu_state.regs[reg].w); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opCMP_l_rmw_a16(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_16(fetchdat); + dst = geteal(); if (abrt) return 1; + setsub32(dst, cpu_state.regs[reg].l); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opCMP_l_rmw_a32(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_32(fetchdat); + dst = geteal(); if (abrt) return 1; + setsub32(dst, cpu_state.regs[reg].l); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opCMP_b_rm_a16(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_16(fetchdat); + src = geteab(); if (abrt) return 1; + setsub8(getr8(reg), src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); + return 0; +} +static int opCMP_b_rm_a32(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_32(fetchdat); + src = geteab(); if (abrt) return 1; + setsub8(getr8(reg), src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); + return 0; +} + +static int opCMP_w_rm_a16(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_16(fetchdat); + src = geteaw(); if (abrt) return 1; + setsub16(cpu_state.regs[reg].w, src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); + return 0; +} +static int opCMP_w_rm_a32(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_32(fetchdat); + src = geteaw(); if (abrt) return 1; + setsub16(cpu_state.regs[reg].w, src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); + return 0; +} + +static int opCMP_l_rm_a16(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_16(fetchdat); + src = geteal(); if (abrt) return 1; + setsub32(cpu_state.regs[reg].l, src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rml); + return 0; +} +static int opCMP_l_rm_a32(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_32(fetchdat); + src = geteal(); if (abrt) return 1; + setsub32(cpu_state.regs[reg].l, src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rml); + return 0; +} + +static int opCMP_AL_imm(uint32_t fetchdat) +{ + uint8_t src = getbytef(); + setsub8(AL, src); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opCMP_AX_imm(uint32_t fetchdat) +{ + uint16_t src = getwordf(); + setsub16(AX, src); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opCMP_EAX_imm(uint32_t fetchdat) +{ + uint32_t src = getlong(); if (abrt) return 1; + setsub32(EAX, src); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opTEST_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + temp2 = getr8(reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opTEST_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + temp2 = getr8(reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opTEST_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + temp2 = cpu_state.regs[reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opTEST_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + temp2 = cpu_state.regs[reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opTEST_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + temp2 = cpu_state.regs[reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opTEST_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + temp2 = cpu_state.regs[reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opTEST_AL(uint32_t fetchdat) +{ + uint8_t temp = getbytef(); + setznp8(AL & temp); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opTEST_AX(uint32_t fetchdat) +{ + uint16_t temp = getwordf(); + setznp16(AX & temp); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opTEST_EAX(uint32_t fetchdat) +{ + uint32_t temp = getlong(); if (abrt) return 1; + setznp32(EAX & temp); + CLOCK_CYCLES(timing_rr); + return 0; +} + + +#define ARITH_MULTI(ea_width, flag_width) \ + dst = getea ## ea_width(); if (abrt) return 1; \ + switch (rmdat&0x38) \ + { \ + case 0x00: /*ADD ea, #*/ \ + setea ## ea_width(dst + src); if (abrt) return 1; \ + setadd ## flag_width(dst, src); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x08: /*OR ea, #*/ \ + dst |= src; \ + setea ## ea_width(dst); if (abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x10: /*ADC ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst + src + tempc); if (abrt) return 1; \ + setadc ## flag_width(dst, src); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x18: /*SBB ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst - (src + tempc)); if (abrt) return 1; \ + setsbc ## flag_width(dst, src); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x20: /*AND ea, #*/ \ + dst &= src; \ + setea ## ea_width(dst); if (abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x28: /*SUB ea, #*/ \ + setea ## ea_width(dst - src); if (abrt) return 1; \ + setsub ## flag_width(dst, src); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x30: /*XOR ea, #*/ \ + dst ^= src; \ + setea ## ea_width(dst); if (abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x38: /*CMP ea, #*/ \ + setsub ## flag_width(dst, src); \ + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); \ + else CLOCK_CYCLES((mod == 3) ? 2 : 7); \ + break; \ + } + + +static int op80_a16(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (abrt) return 1; + ARITH_MULTI(b, 8); + + return 0; +} +static int op80_a32(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (abrt) return 1; + ARITH_MULTI(b, 8); + + return 0; +} +static int op81_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getword(); if (abrt) return 1; + ARITH_MULTI(w, 16); + + return 0; +} +static int op81_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getword(); if (abrt) return 1; + ARITH_MULTI(w, 16); + + return 0; +} +static int op81_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getlong(); if (abrt) return 1; + ARITH_MULTI(l, 32); + + return 0; +} +static int op81_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getlong(); if (abrt) return 1; + ARITH_MULTI(l, 32); + + return 0; +} + +static int op83_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + + return 0; +} +static int op83_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + + return 0; +} + +static int op83_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + + return 0; +} +static int op83_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + + return 0; +} + diff --git a/src/x86_ops_atomic.h b/src/x86_ops_atomic.h new file mode 100644 index 000000000..74b161909 --- /dev/null +++ b/src/x86_ops_atomic.h @@ -0,0 +1,278 @@ +static int opCMPXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + if (AL == temp) seteab(getr8(reg)); + else AL = temp; + if (abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + if (AL == temp) seteab(getr8(reg)); + else AL = temp; + if (abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + if (AX == temp) seteaw(cpu_state.regs[reg].w); + else AX = temp; + if (abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + if (AX == temp) seteaw(cpu_state.regs[reg].w); + else AX = temp; + if (abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + if (EAX == temp) seteal(cpu_state.regs[reg].l); + else EAX = temp; + if (abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + if (EAX == temp) seteal(cpu_state.regs[reg].l); + else EAX = temp; + if (abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG8B_a16(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + temp = geteal(); + temp_hi = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + if (EAX == temp && EDX == temp_hi) + { + seteal(EBX); + writememl(easeg, eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + flags |= Z_FLAG; + else + flags &= ~Z_FLAG; + cycles -= (mod == 3) ? 6 : 10; + return 0; +} +static int opCMPXCHG8B_a32(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + temp = geteal(); + temp_hi = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + if (EAX == temp && EDX == temp_hi) + { + seteal(EBX); + writememl(easeg, eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + flags |= Z_FLAG; + else + flags &= ~Z_FLAG; + cycles -= (mod == 3) ? 6 : 10; + return 0; +} + +static int opXADD_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + seteab(temp + getr8(reg)); if (abrt) return 1; + setadd8(temp, getr8(reg)); + setr8(reg, temp); + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + seteab(temp + getr8(reg)); if (abrt) return 1; + setadd8(temp, getr8(reg)); + setr8(reg, temp); + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + seteaw(temp + cpu_state.regs[reg].w); if (abrt) return 1; + setadd16(temp, cpu_state.regs[reg].w); + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + seteaw(temp + cpu_state.regs[reg].w); if (abrt) return 1; + setadd16(temp, cpu_state.regs[reg].w); + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + seteal(temp + cpu_state.regs[reg].l); if (abrt) return 1; + setadd32(temp, cpu_state.regs[reg].l); + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + seteal(temp + cpu_state.regs[reg].l); if (abrt) return 1; + setadd32(temp, cpu_state.regs[reg].l); + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} diff --git a/src/x86_ops_bcd.h b/src/x86_ops_bcd.h new file mode 100644 index 000000000..37647005b --- /dev/null +++ b/src/x86_ops_bcd.h @@ -0,0 +1,107 @@ +static int opAAA(uint32_t fetchdat) +{ + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL += 6; + AH++; + flags |= (A_FLAG | C_FLAG); + } + else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + CLOCK_CYCLES(is486 ? 3 : 4); + return 0; +} + +static int opAAD(uint32_t fetchdat) +{ + int base = getbytef(); + if (cpu_manufacturer != MANU_INTEL) base = 10; + AL = (AH * base) + AL; + AH = 0; + setznp16(AX); + CLOCK_CYCLES((is486) ? 14 : 19); + return 0; +} + +static int opAAM(uint32_t fetchdat) +{ + int base = getbytef(); + if (!base || cpu_manufacturer != MANU_INTEL) base = 10; + AH = AL / base; + AL %= base; + setznp16(AX); + CLOCK_CYCLES((is486) ? 15 : 17); + return 0; +} + +static int opAAS(uint32_t fetchdat) +{ + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL -= 6; + AH--; + flags |= (A_FLAG | C_FLAG); + } + else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + CLOCK_CYCLES(is486 ? 3 : 4); + return 0; +} + +static int opDAA(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) + 6; + AL += 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9f)) + { + AL += 0x60; + flags |= C_FLAG; + } + + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + flags |= tempw; + CLOCK_CYCLES(4); + + return 0; +} + +static int opDAS(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) - 6; + AL -= 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9f)) + { + AL -= 0x60; + flags |= C_FLAG; + } + + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + flags |= tempw; + CLOCK_CYCLES(4); + + return 0; +} diff --git a/src/x86_ops_bit.h b/src/x86_ops_bit.h new file mode 100644 index 000000000..c5da6967c --- /dev/null +++ b/src/x86_ops_bit.h @@ -0,0 +1,297 @@ +static int opBT_w_r_a16(uint32_t fetchdat) +{ + int tempc; + uint16_t temp; + + fetch_ea_16(fetchdat); + eaaddr += ((cpu_state.regs[reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[reg].w & 15))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + return 0; +} +static int opBT_w_r_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + eaaddr += ((cpu_state.regs[reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[reg].w & 15))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + return 0; +} +static int opBT_l_r_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + eaaddr += ((cpu_state.regs[reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[reg].l & 31))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + return 0; +} +static int opBT_l_r_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + eaaddr += ((cpu_state.regs[reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[reg].l & 31))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + return 0; +} + +#define opBT(name, operation) \ + static int opBT ## name ## _w_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_16(fetchdat); \ + eaaddr += ((cpu_state.regs[reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[reg].w & 15)); \ + seteaw(temp); if (abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + return 0; \ + } \ + static int opBT ## name ## _w_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_32(fetchdat); \ + eaaddr += ((cpu_state.regs[reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[reg].w & 15)); \ + seteaw(temp); if (abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_16(fetchdat); \ + eaaddr += ((cpu_state.regs[reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[reg].l & 31)); \ + seteal(temp); if (abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_32(fetchdat); \ + eaaddr += ((cpu_state.regs[reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[reg].l & 31)); \ + seteal(temp); if (abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + return 0; \ + } + +opBT(C, ^=) +opBT(R, &=~) +opBT(S, |=) + +static int opBA_w_a16(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_16(fetchdat); + + temp = geteaw(); + count = getbyte(); if (abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + seteaw(temp); if (abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + return 0; +} +static int opBA_w_a32(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_32(fetchdat); + + temp = geteaw(); + count = getbyte(); if (abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + seteaw(temp); if (abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + return 0; +} + +static int opBA_l_a16(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_16(fetchdat); + + temp = geteal(); + count = getbyte(); if (abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + seteal(temp); if (abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + return 0; +} +static int opBA_l_a32(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_32(fetchdat); + + temp = geteal(); + count = getbyte(); if (abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + seteal(temp); if (abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + return 0; +} diff --git a/src/x86_ops_bitscan.h b/src/x86_ops_bitscan.h new file mode 100644 index 000000000..90dc6e8bf --- /dev/null +++ b/src/x86_ops_bitscan.h @@ -0,0 +1,117 @@ +#define BS_common(start, end, dir, dest, time) \ + flags_rebuild(); \ + if (temp) \ + { \ + int c; \ + flags &= ~Z_FLAG; \ + for (c = start; c != end; c += dir) \ + { \ + CLOCK_CYCLES(time); \ + if (temp & (1 << c)) \ + { \ + dest = c; \ + break; \ + } \ + } \ + } \ + else \ + flags |= Z_FLAG; + +static int opBSF_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + + BS_common(0, 16, 1, cpu_state.regs[reg].w, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSF_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + + BS_common(0, 16, 1, cpu_state.regs[reg].w, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSF_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + + BS_common(0, 32, 1, cpu_state.regs[reg].l, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSF_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + + BS_common(0, 32, 1, cpu_state.regs[reg].l, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} + +static int opBSR_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + + BS_common(15, -1, -1, cpu_state.regs[reg].w, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSR_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + + BS_common(15, -1, -1, cpu_state.regs[reg].w, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSR_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + + BS_common(31, -1, -1, cpu_state.regs[reg].l, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSR_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + + BS_common(31, -1, -1, cpu_state.regs[reg].l, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} + diff --git a/src/x86_ops_call.h b/src/x86_ops_call.h new file mode 100644 index 000000000..ecc0a303b --- /dev/null +++ b/src/x86_ops_call.h @@ -0,0 +1,348 @@ +#define CALL_FAR_w(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate32) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (abrt) { ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (abrt) { ESP = old_esp; return 1; } \ + } + +#define CALL_FAR_l(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate16) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (abrt) { ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (abrt) { ESP = old_esp; return 1; } \ + } + + +static int opCALL_far_w(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint16_t new_cs, new_pc; + + new_pc = getwordf(); + new_cs = getword(); if (abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + + return 0; +} +static int opCALL_far_l(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint32_t new_cs, new_pc; + + new_pc = getlong(); + new_cs = getword(); if (abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + + return 0; +} + + +static int opFF_w_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint16_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + temp = geteaw(); if (abrt) return 1; + seteaw(temp + 1); if (abrt) return 1; + setadd16nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x08: /*DEC w*/ + temp = geteaw(); if (abrt) return 1; + seteaw(temp - 1); if (abrt) return 1; + setsub16nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x10: /*CALL*/ + new_pc = geteaw(); if (abrt) return 1; + PUSH_W(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + break; + case 0x20: /*JMP*/ + new_pc = geteaw(); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 1; + CPU_BLOCK_END(); + break; + case 0x30: /*PUSH w*/ + temp = geteaw(); if (abrt) return 1; + PUSH_W(temp); + CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return abrt; +} +static int opFF_w_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint16_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + temp = geteaw(); if (abrt) return 1; + seteaw(temp + 1); if (abrt) return 1; + setadd16nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x08: /*DEC w*/ + temp = geteaw(); if (abrt) return 1; + seteaw(temp - 1); if (abrt) return 1; + setsub16nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x10: /*CALL*/ + new_pc = geteaw(); if (abrt) return 1; + PUSH_W(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + break; + case 0x20: /*JMP*/ + new_pc = geteaw(); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 1; + CPU_BLOCK_END(); + break; + case 0x30: /*PUSH w*/ + temp = geteaw(); if (abrt) return 1; + PUSH_W(temp); + CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return abrt; +} + +static int opFF_l_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint32_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + temp = geteal(); if (abrt) return 1; + seteal(temp + 1); if (abrt) return 1; + setadd32nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x08: /*DEC l*/ + temp = geteal(); if (abrt) return 1; + seteal(temp - 1); if (abrt) return 1; + setsub32nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x10: /*CALL*/ + new_pc = geteal(); if (abrt) return 1; + PUSH_L(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + break; + case 0x20: /*JMP*/ + new_pc = geteal(); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 1; + CPU_BLOCK_END(); + break; + case 0x30: /*PUSH l*/ + temp = geteal(); if (abrt) return 1; + PUSH_L(temp); + CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return abrt; +} +static int opFF_l_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint32_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + temp = geteal(); if (abrt) return 1; + seteal(temp + 1); if (abrt) return 1; + setadd32nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x08: /*DEC l*/ + temp = geteal(); if (abrt) return 1; + seteal(temp - 1); if (abrt) return 1; + setsub32nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x10: /*CALL*/ + new_pc = geteal(); if (abrt) return 1; + PUSH_L(cpu_state.pc); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + break; + case 0x20: /*JMP*/ + new_pc = geteal(); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 1; + CPU_BLOCK_END(); + break; + case 0x30: /*PUSH l*/ + temp = geteal(); if (abrt) return 1; + PUSH_L(temp); + CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return abrt; +} diff --git a/src/x86_ops_flag.h b/src/x86_ops_flag.h new file mode 100644 index 000000000..6f4a2e800 --- /dev/null +++ b/src/x86_ops_flag.h @@ -0,0 +1,190 @@ +static int opCMC(uint32_t fetchdat) +{ + flags_rebuild(); + flags ^= C_FLAG; + CLOCK_CYCLES(2); + return 0; +} + + +static int opCLC(uint32_t fetchdat) +{ + flags_rebuild(); + flags &= ~C_FLAG; + CLOCK_CYCLES(2); + return 0; +} +static int opCLD(uint32_t fetchdat) +{ + flags &= ~D_FLAG; + CLOCK_CYCLES(2); + return 0; +} +static int opCLI(uint32_t fetchdat) +{ + if (!IOPLp) + { + x86gpf(NULL,0); + return 1; + } + else + flags &= ~I_FLAG; + + CPU_BLOCK_END(); + + CLOCK_CYCLES(3); + return 0; +} + +static int opSTC(uint32_t fetchdat) +{ + flags_rebuild(); + flags |= C_FLAG; + CLOCK_CYCLES(2); + return 0; +} +static int opSTD(uint32_t fetchdat) +{ + flags |= D_FLAG; + CLOCK_CYCLES(2); + return 0; +} +static int opSTI(uint32_t fetchdat) +{ + if (!IOPLp) + { + x86gpf(NULL,0); + return 1; + } + else + flags |= I_FLAG; + + CPU_BLOCK_END(); + + CLOCK_CYCLES(2); + return 0; +} + +static int opSAHF(uint32_t fetchdat) +{ + flags_rebuild(); + flags = (flags & 0xff00) | (AH & 0xd5) | 2; + CLOCK_CYCLES(3); + + codegen_flags_changed = 0; + + return 0; +} +static int opLAHF(uint32_t fetchdat) +{ + flags_rebuild(); + AH = flags & 0xff; + CLOCK_CYCLES(3); + return 0; +} + +static int opPUSHF(uint32_t fetchdat) +{ + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL,0); + return 1; + } + flags_rebuild(); + PUSH_W(flags); + CLOCK_CYCLES(4); + return abrt; +} +static int opPUSHFD(uint32_t fetchdat) +{ + uint16_t tempw; + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + if (CPUID) tempw = eflags & 0x24; + else tempw = eflags & 4; + flags_rebuild(); + PUSH_L(flags | (tempw << 16)); + CLOCK_CYCLES(4); + return abrt; +} + +static int opPOPF_286(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + tempw = POP_W(); if (abrt) return 1; + + if (!(msw & 1)) flags = (flags & 0x7000) | (tempw & 0x0fd5) | 2; + else if (!(CPL)) flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + flags_extract(); + + CLOCK_CYCLES(5); + + codegen_flags_changed = 0; + + return 0; +} +static int opPOPF(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + tempw = POP_W(); if (abrt) return 1; + + if (!(CPL) || !(msw & 1)) flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + flags_extract(); + + CLOCK_CYCLES(5); + + codegen_flags_changed = 0; + + return 0; +} +static int opPOPFD(uint32_t fetchdat) +{ + uint32_t templ; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + templ = POP_L(); if (abrt) return 1; + + if (!(CPL) || !(msw & 1)) flags = (templ & 0x7fd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (templ & 0x4fd5) | 2; + else flags = (flags & 0x3200) | (templ & 0x4dd5) | 2; + + templ &= is486 ? 0x240000 : 0; + templ |= ((eflags&3) << 16); + if (CPUID) eflags = (templ >> 16) & 0x27; + else if (is486) eflags = (templ >> 16) & 7; + else eflags = (templ >> 16) & 3; + + flags_extract(); + + CLOCK_CYCLES(5); + + codegen_flags_changed = 0; + + return 0; +} diff --git a/src/x86_ops_fpu.h b/src/x86_ops_fpu.h new file mode 100644 index 000000000..8c264374f --- /dev/null +++ b/src/x86_ops_fpu.h @@ -0,0 +1,82 @@ +static int opESCAPE_d8_a16(uint32_t fetchdat) +{ + return x86_opcodes_d8_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_d8_a32(uint32_t fetchdat) +{ + return x86_opcodes_d8_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_d9_a16(uint32_t fetchdat) +{ + return x86_opcodes_d9_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_d9_a32(uint32_t fetchdat) +{ + return x86_opcodes_d9_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_da_a16(uint32_t fetchdat) +{ + return x86_opcodes_da_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_da_a32(uint32_t fetchdat) +{ + return x86_opcodes_da_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_db_a16(uint32_t fetchdat) +{ + return x86_opcodes_db_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_db_a32(uint32_t fetchdat) +{ + return x86_opcodes_db_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_dc_a16(uint32_t fetchdat) +{ + return x86_opcodes_dc_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_dc_a32(uint32_t fetchdat) +{ + return x86_opcodes_dc_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_dd_a16(uint32_t fetchdat) +{ + return x86_opcodes_dd_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_dd_a32(uint32_t fetchdat) +{ + return x86_opcodes_dd_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_de_a16(uint32_t fetchdat) +{ + return x86_opcodes_de_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_de_a32(uint32_t fetchdat) +{ + return x86_opcodes_de_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_df_a16(uint32_t fetchdat) +{ + return x86_opcodes_df_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_df_a32(uint32_t fetchdat) +{ + return x86_opcodes_df_a32[fetchdat & 0xff](fetchdat); +} + +static int opWAIT(uint32_t fetchdat) +{ + if ((cr0 & 0xa) == 0xa) + { + x86_int(7); + return 1; + } + CLOCK_CYCLES(4); + return 0; +} diff --git a/src/x86_ops_i686.h b/src/x86_ops_i686.h new file mode 100644 index 000000000..5888b1d66 --- /dev/null +++ b/src/x86_ops_i686.h @@ -0,0 +1,651 @@ +static int internal_illegal() +{ + cpu_state.pc = oldpc; + x86gpf(NULL, 0); + return 1; +} + +/* 0 = Limit 0-15 + 1 = Base 0-15 + 2 = Base 16-23 (bits 0-7), Access rights + 8-11 Type + 12 S + 13, 14 DPL + 15 P + 3 = Limit 16-19 (bits 0-3), Base 24-31 (bits 8-15), granularity, etc. + 4 A + 6 DB + 7 G */ + +static void make_seg_data(uint16_t *seg_data, uint32_t base, uint32_t limit, uint8_t type, uint8_t s, uint8_t dpl, uint8_t p, uint8_t g, uint8_t db, uint8_t a) +{ + seg_data[0] = limit & 0xFFFF; + seg_data[1] = base & 0xFFFF; + seg_data[2] = ((base >> 16) & 0xFF) | (type << 8) | (p << 15) | (dpl << 13) | (s << 12); + seg_data[3] = ((limit >> 16) & 0xF) | (a << 4) | (db << 6) | (g << 7) | ((base >> 16) & 0xFF00); +} + +static int opSYSENTER(uint32_t fetchdat) +{ + uint16_t sysenter_cs_seg_data[4]; + uint16_t sysenter_ss_seg_data[4]; + + pclog("SYSENTER called\n"); + + if (!(cr0 & 1)) return internal_illegal(); + if (!(cs_msr & 0xFFFC)) return internal_illegal(); + + pclog("SYSENTER started:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); + + ESP = esp_msr; + cpu_state.pc = eip_msr; + + /* Set VM, RF, and IF to 0. */ + eflags &= ~0x0003; + flags &= ~0x0200; + + CS = (cs_msr & 0xFFFC); + make_seg_data(sysenter_cs_seg_data, 0, 0xFFFFF, 11, 1, 0, 1, 1, 1, 0); + do_seg_load(&_cs, sysenter_cs_seg_data); + use32 = 0x300; + + SS = ((cs_msr + 8) & 0xFFFC); + make_seg_data(sysenter_ss_seg_data, 0, 0xFFFFF, 3, 1, 0, 1, 1, 1, 0); + do_seg_load(&_ss, sysenter_ss_seg_data); + stack32 = 1; + + cycles -= timing_jmp_pm; + + CPU_BLOCK_END(); + + pclog("SYSENTER completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); + + return 0; +} + +static int opSYSEXIT(uint32_t fetchdat) +{ + uint16_t sysexit_cs_seg_data[4]; + uint16_t sysexit_ss_seg_data[4]; + + pclog("SYSEXIT called\n"); + + if (!(cs_msr & 0xFFFC)) return internal_illegal(); + if (!(cr0 & 1)) return internal_illegal(); + if (CS & 3) return internal_illegal(); + + pclog("SYSEXIT completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); + + ESP = ECX; + cpu_state.pc = EDX; + + CS = ((cs_msr + 16) & 0xFFFC) | 3; + make_seg_data(sysexit_cs_seg_data, 0, 0xFFFFF, 11, 1, 3, 1, 1, 1, 0); + do_seg_load(&_cs, sysexit_cs_seg_data); + use32 = 0x300; + + SS = CS + 8; + make_seg_data(sysexit_ss_seg_data, 0, 0xFFFFF, 3, 1, 3, 1, 1, 1, 0); + do_seg_load(&_ss, sysexit_ss_seg_data); + stack32 = 1; + + flushmmucache_cr3(); + + cycles -= timing_jmp_pm; + + CPU_BLOCK_END(); + + pclog("SYSEXIT completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); + + return 0; +} + +static int opFXSAVESTOR_a16(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint16_t old_eaaddr = 0; + int old_ismmx = ismmx; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_16(fetchdat); + + if (eaaddr & 0xf) + { + pclog("Effective address %04X not on 16-byte boundary\n", eaaddr); + x86gpf(NULL, 0); + return 1; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (mod == 3)) + { + if (fxinst > 1) pclog("FX instruction is: %02X\n", fxinst); + if (mod == 3) pclog("MOD is 3\n"); + + cpu_state.pc = oldpc; + + x86illegal(); + return 0; + } + + FP_ENTER(); + + old_eaaddr = eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + // pclog("FXRSTOR issued\n"); + + npxc = readmemw(easeg, eaaddr); + fpus = readmemw(easeg, eaaddr + 2); + npxc = (npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + TOP = (fpus >> 11) & 7; + npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, eaaddr+8); + x87_pc_seg = readmemw(easeg, eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, eaaddr+16); + x87_op_off |= (readmemw(easeg, eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + eaaddr = old_eaaddr + 32; + x87_ldmmx(&MM[0]); x87_ld_frstor(0); + + eaaddr = old_eaaddr + 48; + x87_ldmmx(&MM[1]); x87_ld_frstor(1); + + eaaddr = old_eaaddr + 64; + x87_ldmmx(&MM[2]); x87_ld_frstor(2); + + eaaddr = old_eaaddr + 80; + x87_ldmmx(&MM[3]); x87_ld_frstor(3); + + eaaddr = old_eaaddr + 96; + x87_ldmmx(&MM[4]); x87_ld_frstor(4); + + eaaddr = old_eaaddr + 112; + x87_ldmmx(&MM[5]); x87_ld_frstor(5); + + eaaddr = old_eaaddr + 128; + x87_ldmmx(&MM[6]); x87_ld_frstor(6); + + eaaddr = old_eaaddr + 144; + x87_ldmmx(&MM[7]); x87_ld_frstor(7); + + ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + if (MM[0].w[4] == 0xffff && MM[1].w[4] == 0xffff && MM[2].w[4] == 0xffff && MM[3].w[4] == 0xffff && + MM[4].w[4] == 0xffff && MM[5].w[4] == 0xffff && MM[6].w[4] == 0xffff && MM[7].w[4] == 0xffff && + !TOP && !(*(uint64_t *)tag)) + ismmx = old_ismmx; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(abrt) pclog("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + // pclog("FXSAVE issued\n"); + + if (twd & 0x0003 == 0x0003) ftwb |= 0x01; + if (twd & 0x000C == 0x000C) ftwb |= 0x02; + if (twd & 0x0030 == 0x0030) ftwb |= 0x04; + if (twd & 0x00C0 == 0x00C0) ftwb |= 0x08; + if (twd & 0x0300 == 0x0300) ftwb |= 0x10; + if (twd & 0x0C00 == 0x0C00) ftwb |= 0x20; + if (twd & 0x3000 == 0x3000) ftwb |= 0x40; + if (twd & 0xC000 == 0xC000) ftwb |= 0x80; + + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememb(easeg,eaaddr+4,ftwb); + + writememw(easeg,eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,eaaddr+8,x87_pc_off); + writememw(easeg,eaaddr+12,x87_pc_seg); + + writememl(easeg,eaaddr+16,x87_op_off); + writememw(easeg,eaaddr+20,x87_op_seg); + + eaaddr = old_eaaddr + 32; + ismmx ? x87_stmmx(MM[0]) : x87_st_fsave(0); + + eaaddr = old_eaaddr + 48; + ismmx ? x87_stmmx(MM[1]) : x87_st_fsave(1); + + eaaddr = old_eaaddr + 64; + ismmx ? x87_stmmx(MM[2]) : x87_st_fsave(2); + + eaaddr = old_eaaddr + 80; + ismmx ? x87_stmmx(MM[3]) : x87_st_fsave(3); + + eaaddr = old_eaaddr + 96; + ismmx ? x87_stmmx(MM[4]) : x87_st_fsave(4); + + eaaddr = old_eaaddr + 112; + ismmx ? x87_stmmx(MM[5]) : x87_st_fsave(5); + + eaaddr = old_eaaddr + 128; + ismmx ? x87_stmmx(MM[6]) : x87_st_fsave(6); + + eaaddr = old_eaaddr + 144; + ismmx ? x87_stmmx(MM[7]) : x87_st_fsave(7); + + eaaddr = old_eaaddr; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(abrt) pclog("FXSAVE: abrt != 0\n"); + } + + return abrt; +} + +static int opFXSAVESTOR_a32(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint32_t old_eaaddr = 0; + int old_ismmx = ismmx; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_32(fetchdat); + + if (eaaddr & 0xf) + { + pclog("Effective address %08X not on 16-byte boundary\n", eaaddr); + x86gpf(NULL, 0); + return 1; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (mod == 3)) + { + if (fxinst > 1) pclog("FX instruction is: %02X\n", fxinst); + if (mod == 3) pclog("MOD is 3\n"); + + cpu_state.pc = oldpc; + + x86illegal(); + return 0; + } + + FP_ENTER(); + + old_eaaddr = eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + // pclog("FXRSTOR issued\n"); + + npxc = readmemw(easeg, eaaddr); + fpus = readmemw(easeg, eaaddr + 2); + npxc = (npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + TOP = (fpus >> 11) & 7; + npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, eaaddr+8); + x87_pc_seg = readmemw(easeg, eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, eaaddr+16); + x87_op_off |= (readmemw(easeg, eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + eaaddr = old_eaaddr + 32; + x87_ldmmx(&MM[0]); x87_ld_frstor(0); + + eaaddr = old_eaaddr + 48; + x87_ldmmx(&MM[1]); x87_ld_frstor(1); + + eaaddr = old_eaaddr + 64; + x87_ldmmx(&MM[2]); x87_ld_frstor(2); + + eaaddr = old_eaaddr + 80; + x87_ldmmx(&MM[3]); x87_ld_frstor(3); + + eaaddr = old_eaaddr + 96; + x87_ldmmx(&MM[4]); x87_ld_frstor(4); + + eaaddr = old_eaaddr + 112; + x87_ldmmx(&MM[5]); x87_ld_frstor(5); + + eaaddr = old_eaaddr + 128; + x87_ldmmx(&MM[6]); x87_ld_frstor(6); + + eaaddr = old_eaaddr + 144; + x87_ldmmx(&MM[7]); x87_ld_frstor(7); + + ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + if (MM[0].w[4] == 0xffff && MM[1].w[4] == 0xffff && MM[2].w[4] == 0xffff && MM[3].w[4] == 0xffff && + MM[4].w[4] == 0xffff && MM[5].w[4] == 0xffff && MM[6].w[4] == 0xffff && MM[7].w[4] == 0xffff && + !TOP && !(*(uint64_t *)tag)) + ismmx = old_ismmx; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(abrt) pclog("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + // pclog("FXSAVE issued\n"); + + if (twd & 0x0003 == 0x0003) ftwb |= 0x01; + if (twd & 0x000C == 0x000C) ftwb |= 0x02; + if (twd & 0x0030 == 0x0030) ftwb |= 0x04; + if (twd & 0x00C0 == 0x00C0) ftwb |= 0x08; + if (twd & 0x0300 == 0x0300) ftwb |= 0x10; + if (twd & 0x0C00 == 0x0C00) ftwb |= 0x20; + if (twd & 0x3000 == 0x3000) ftwb |= 0x40; + if (twd & 0xC000 == 0xC000) ftwb |= 0x80; + + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememb(easeg,eaaddr+4,ftwb); + + writememw(easeg,eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,eaaddr+8,x87_pc_off); + writememw(easeg,eaaddr+12,x87_pc_seg); + + writememl(easeg,eaaddr+16,x87_op_off); + writememw(easeg,eaaddr+20,x87_op_seg); + + eaaddr = old_eaaddr + 32; + ismmx ? x87_stmmx(MM[0]) : x87_st_fsave(0); + + eaaddr = old_eaaddr + 48; + ismmx ? x87_stmmx(MM[1]) : x87_st_fsave(1); + + eaaddr = old_eaaddr + 64; + ismmx ? x87_stmmx(MM[2]) : x87_st_fsave(2); + + eaaddr = old_eaaddr + 80; + ismmx ? x87_stmmx(MM[3]) : x87_st_fsave(3); + + eaaddr = old_eaaddr + 96; + ismmx ? x87_stmmx(MM[4]) : x87_st_fsave(4); + + eaaddr = old_eaaddr + 112; + ismmx ? x87_stmmx(MM[5]) : x87_st_fsave(5); + + eaaddr = old_eaaddr + 128; + ismmx ? x87_stmmx(MM[6]) : x87_st_fsave(6); + + eaaddr = old_eaaddr + 144; + ismmx ? x87_stmmx(MM[7]) : x87_st_fsave(7); + + eaaddr = old_eaaddr; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(abrt) pclog("FXSAVE: abrt != 0\n"); + } + + return abrt; +} + +#define AMD_SYSCALL_EIP (star & 0xFFFFFFFF) +#define AMD_SYSCALL_SB ((star >> 32) & 0xFFFF) +#define AMD_SYSRET_SB ((star >> 48) & 0xFFFF) + +/* 0F 05 */ +static int opSYSCALL(uint32_t fetchdat) +{ + uint16_t syscall_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t syscall_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!(cr0 & 1)) return internal_illegal(); + if (!AMD_SYSCALL_SB) return internal_illegal(); + + /* Set VM, IF, RF to 0. */ + /* eflags &= ~0x00030200; + flags &= ~0x0200; */ + + /* Let's do this by the AMD spec. */ + ECX = cpu_state.pc; + cpu_state.pc = AMD_SYSCALL_EIP; + + eflags &= ~0x0002; + flags &= ~0x0200; + + /* CS */ + _cs.seg = AMD_SYSCALL_SB & ~7; + if (cs_msr & 4) + { + if (_cs.seg >= ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",cs_msr,ldt.limit); + x86gpf(NULL, cs_msr & ~3); + return 1; + } + _cs.seg +=ldt.base; + } + else + { + if (_cs.seg >= gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",cs_msr,gdt.limit); + x86gpf(NULL, cs_msr & ~3); + return 1; + } + _cs.seg += gdt.base; + } + cpl_override = 1; + + syscall_cs_seg_data[0] = 0xFFFF; + syscall_cs_seg_data[1] = 0; + syscall_cs_seg_data[2] = 0x9B00; + syscall_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSCALL_SB & ~3) | 0; + + do_seg_load(&_cs, syscall_cs_seg_data); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 0; + + _cs.limit = 0xFFFFFFFF; + _cs.limit_high = 0xFFFFFFFF; + + /* SS */ + syscall_ss_seg_data[0] = 0xFFFF; + syscall_ss_seg_data[1] = 0; + syscall_ss_seg_data[2] = 0x9300; + syscall_ss_seg_data[3] = 0xC0; + do_seg_load(&_ss, syscall_ss_seg_data); + _ss.seg = (AMD_SYSCALL_SB + 8) & 0xFFFC; + stack32 = 1; + + _ss.limit = 0xFFFFFFFF; + _ss.limit_high = 0xFFFFFFFF; + + _ss.checked = 0; + + cpu_state.pc = eip_msr; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + /* pclog("SYSCALL completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eflags=%04X flags=%04X use32=%04X stack32=%i\n", eflags, flags, use32, stack32); */ + + return 0; +} + +/* 0F 07 */ +static int opSYSRET(uint32_t fetchdat) +{ + uint16_t sysret_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t sysret_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!cs_msr) return internal_illegal(); + if (!(cr0 & 1)) return internal_illegal(); + + cpu_state.pc = ECX; + + eflags |= (1 << 1); + + /* CS */ + _cs.seg = AMD_SYSRET_SB & ~7; + if (cs_msr & 4) + { + if (_cs.seg >= ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",cs_msr,ldt.limit); + x86gpf(NULL, cs_msr & ~3); + return 1; + } + _cs.seg +=ldt.base; + } + else + { + if (_cs.seg >= gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",cs_msr,gdt.limit); + x86gpf(NULL, cs_msr & ~3); + return 1; + } + _cs.seg += gdt.base; + } + cpl_override = 1; + + sysret_cs_seg_data[0] = 0xFFFF; + sysret_cs_seg_data[1] = 0; + sysret_cs_seg_data[2] = 0xFB00; + sysret_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSRET_SB & ~3) | 3; + + do_seg_load(&_cs, sysret_cs_seg_data); + flushmmucache_cr3(); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 3; + + _cs.limit = 0xFFFFFFFF; + _cs.limit_high = 0xFFFFFFFF; + + /* SS */ + sysret_ss_seg_data[0] = 0xFFFF; + sysret_ss_seg_data[1] = 0; + sysret_ss_seg_data[2] = 0xF300; + sysret_ss_seg_data[3] = 0xC0; + do_seg_load(&_ss, sysret_ss_seg_data); + _ss.seg = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; + stack32 = 1; + + _ss.limit = 0xFFFFFFFF; + _ss.limit_high = 0xFFFFFFFF; + + _ss.checked = 0; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + /* pclog("SYSRET completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", eflags, flags, use32, stack32, ECX, EDX); */ + + return 0; +} diff --git a/src/x86_ops_inc_dec.h b/src/x86_ops_inc_dec.h new file mode 100644 index 000000000..be4017bf2 --- /dev/null +++ b/src/x86_ops_inc_dec.h @@ -0,0 +1,86 @@ +#define INC_DEC_OP(name, reg, inc, setflags) \ + static int op ## name (uint32_t fetchdat) \ + { \ + setflags(reg, 1); \ + reg += inc; \ + CLOCK_CYCLES(timing_rr); \ + return 0; \ + } + +INC_DEC_OP(INC_AX, AX, 1, setadd16nc) +INC_DEC_OP(INC_BX, BX, 1, setadd16nc) +INC_DEC_OP(INC_CX, CX, 1, setadd16nc) +INC_DEC_OP(INC_DX, DX, 1, setadd16nc) +INC_DEC_OP(INC_SI, SI, 1, setadd16nc) +INC_DEC_OP(INC_DI, DI, 1, setadd16nc) +INC_DEC_OP(INC_BP, BP, 1, setadd16nc) +INC_DEC_OP(INC_SP, SP, 1, setadd16nc) + +INC_DEC_OP(INC_EAX, EAX, 1, setadd32nc) +INC_DEC_OP(INC_EBX, EBX, 1, setadd32nc) +INC_DEC_OP(INC_ECX, ECX, 1, setadd32nc) +INC_DEC_OP(INC_EDX, EDX, 1, setadd32nc) +INC_DEC_OP(INC_ESI, ESI, 1, setadd32nc) +INC_DEC_OP(INC_EDI, EDI, 1, setadd32nc) +INC_DEC_OP(INC_EBP, EBP, 1, setadd32nc) +INC_DEC_OP(INC_ESP, ESP, 1, setadd32nc) + +INC_DEC_OP(DEC_AX, AX, -1, setsub16nc) +INC_DEC_OP(DEC_BX, BX, -1, setsub16nc) +INC_DEC_OP(DEC_CX, CX, -1, setsub16nc) +INC_DEC_OP(DEC_DX, DX, -1, setsub16nc) +INC_DEC_OP(DEC_SI, SI, -1, setsub16nc) +INC_DEC_OP(DEC_DI, DI, -1, setsub16nc) +INC_DEC_OP(DEC_BP, BP, -1, setsub16nc) +INC_DEC_OP(DEC_SP, SP, -1, setsub16nc) + +INC_DEC_OP(DEC_EAX, EAX, -1, setsub32nc) +INC_DEC_OP(DEC_EBX, EBX, -1, setsub32nc) +INC_DEC_OP(DEC_ECX, ECX, -1, setsub32nc) +INC_DEC_OP(DEC_EDX, EDX, -1, setsub32nc) +INC_DEC_OP(DEC_ESI, ESI, -1, setsub32nc) +INC_DEC_OP(DEC_EDI, EDI, -1, setsub32nc) +INC_DEC_OP(DEC_EBP, EBP, -1, setsub32nc) +INC_DEC_OP(DEC_ESP, ESP, -1, setsub32nc) + + +static int opINCDEC_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp=geteab(); if (abrt) return 1; + + if (rmdat&0x38) + { + seteab(temp - 1); if (abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (abrt) return 1; + setadd8nc(temp, 1); + } + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + return 0; +} +static int opINCDEC_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp=geteab(); if (abrt) return 1; + + if (rmdat&0x38) + { + seteab(temp - 1); if (abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (abrt) return 1; + setadd8nc(temp, 1); + } + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + return 0; +} diff --git a/src/x86_ops_int - Cópia.h b/src/x86_ops_int - Cópia.h new file mode 100644 index 000000000..0cfb959dd --- /dev/null +++ b/src/x86_ops_int - Cópia.h @@ -0,0 +1,77 @@ +static int opINT3(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(3); + CLOCK_CYCLES((is486) ? 44 : 59); + return 1; +} + +static int opINT(uint32_t fetchdat) +{ + uint8_t temp; + + /*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + temp = getbytef(); +// /*if (temp == 0x10 && AH == 0xe) */pclog("INT %02X : %04X %04X %04X %04X %c %04X:%04X\n", temp, AX, BX, CX, DX, (AL < 32) ? ' ' : AL, CS, pc); +// if (CS == 0x0028 && pc == 0xC03813C0) +// output = 3; +/* if (pc == 0x8028009A) + output = 3; + if (pc == 0x80282B6F) + { + __times++; + if (__times == 2) + fatal("WRONG\n"); + } + if (pc == 0x802809CE) + fatal("RIGHT\n");*/ +// if (CS == 0x0028 && pc == 0x80037FE9) +// output = 3; +//if (CS == 0x9087 && pc == 0x3763) +// fatal("Here\n"); +//if (CS==0x9087 && pc == 0x0850) +// output = 1; + +/* if (output && pc == 0x80033008) + { + __times++; + if (__times == 2) + fatal("WRONG\n"); + }*/ +/* if (output && pc == 0x80D8) + { + __times++; + if (__times == 2) + fatal("RIGHT\n"); + }*/ + + x86_int_sw(temp); + return 1; +} + +static int opINTO(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (VF_SET()) + { + oldpc = pc; + x86_int_sw(4); + return 1; + } + CLOCK_CYCLES(3); + return 0; +} + diff --git a/src/x86_ops_int.h b/src/x86_ops_int.h new file mode 100644 index 000000000..83bcc91d8 --- /dev/null +++ b/src/x86_ops_int.h @@ -0,0 +1,77 @@ +static int opINT3(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(3); + CLOCK_CYCLES((is486) ? 44 : 59); + return 1; +} + +static int opINT(uint32_t fetchdat) +{ + uint8_t temp; + + /*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + temp = getbytef(); +// /*if (temp == 0x10 && AH == 0xe) */pclog("INT %02X : %04X %04X %04X %04X %c %04X:%04X\n", temp, AX, BX, CX, DX, (AL < 32) ? ' ' : AL, CS, pc); +// if (CS == 0x0028 && pc == 0xC03813C0) +// output = 3; +/* if (pc == 0x8028009A) + output = 3; + if (pc == 0x80282B6F) + { + __times++; + if (__times == 2) + fatal("WRONG\n"); + } + if (pc == 0x802809CE) + fatal("RIGHT\n");*/ +// if (CS == 0x0028 && pc == 0x80037FE9) +// output = 3; +//if (CS == 0x9087 && pc == 0x3763) +// fatal("Here\n"); +//if (CS==0x9087 && pc == 0x0850) +// output = 1; + +/* if (output && pc == 0x80033008) + { + __times++; + if (__times == 2) + fatal("WRONG\n"); + }*/ +/* if (output && pc == 0x80D8) + { + __times++; + if (__times == 2) + fatal("RIGHT\n"); + }*/ + + x86_int_sw(temp); + return 1; +} + +static int opINTO(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (VF_SET()) + { + oldpc = cpu_state.pc; + x86_int_sw(4); + return 1; + } + CLOCK_CYCLES(3); + return 0; +} + diff --git a/src/x86_ops_io - Cópia.h b/src/x86_ops_io - Cópia.h new file mode 100644 index 000000000..c7bde30aa --- /dev/null +++ b/src/x86_ops_io - Cópia.h @@ -0,0 +1,112 @@ +static int opIN_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + AL = inb(port); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + AX = inw(port); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + EAX = inl(port); + CLOCK_CYCLES(12); + return 0; +} + +static int opOUT_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + outb(port, AL); + CLOCK_CYCLES(10); + if (port == 0x64) + return x86_was_reset; + return 0; +} +static int opOUT_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + outw(port, AX); + CLOCK_CYCLES(10); + return 0; +} +static int opOUT_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + outl(port, EAX); + CLOCK_CYCLES(10); + return 0; +} + +static int opIN_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + AL = inb(DX); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + AX = inw(DX); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + EAX = inl(DX); + CLOCK_CYCLES(12); + return 0; +} + +static int opOUT_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + outb(DX, AL); + CLOCK_CYCLES(11); + return x86_was_reset; +} +static int opOUT_AX_DX(uint32_t fetchdat) +{ + //pclog("OUT_AX_DX %04X %04X\n", DX, AX); + check_io_perm(DX); + check_io_perm(DX + 1); + outw(DX, AX); + CLOCK_CYCLES(11); + return 0; +} +static int opOUT_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + outl(DX, EAX); + CLOCK_CYCLES(11); + return 0; +} diff --git a/src/x86_ops_io.h b/src/x86_ops_io.h new file mode 100644 index 000000000..c7bde30aa --- /dev/null +++ b/src/x86_ops_io.h @@ -0,0 +1,112 @@ +static int opIN_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + AL = inb(port); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + AX = inw(port); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + EAX = inl(port); + CLOCK_CYCLES(12); + return 0; +} + +static int opOUT_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + outb(port, AL); + CLOCK_CYCLES(10); + if (port == 0x64) + return x86_was_reset; + return 0; +} +static int opOUT_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + outw(port, AX); + CLOCK_CYCLES(10); + return 0; +} +static int opOUT_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + outl(port, EAX); + CLOCK_CYCLES(10); + return 0; +} + +static int opIN_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + AL = inb(DX); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + AX = inw(DX); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + EAX = inl(DX); + CLOCK_CYCLES(12); + return 0; +} + +static int opOUT_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + outb(DX, AL); + CLOCK_CYCLES(11); + return x86_was_reset; +} +static int opOUT_AX_DX(uint32_t fetchdat) +{ + //pclog("OUT_AX_DX %04X %04X\n", DX, AX); + check_io_perm(DX); + check_io_perm(DX + 1); + outw(DX, AX); + CLOCK_CYCLES(11); + return 0; +} +static int opOUT_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + outl(DX, EAX); + CLOCK_CYCLES(11); + return 0; +} diff --git a/src/x86_ops_jump.h b/src/x86_ops_jump.h new file mode 100644 index 000000000..c2bc1e1ad --- /dev/null +++ b/src/x86_ops_jump.h @@ -0,0 +1,305 @@ +#define cond_O ( VF_SET()) +#define cond_NO (!VF_SET()) +#define cond_B ( CF_SET()) +#define cond_NB (!CF_SET()) +#define cond_E ( ZF_SET()) +#define cond_NE (!ZF_SET()) +#define cond_BE ( CF_SET() || ZF_SET()) +#define cond_NBE (!CF_SET() && !ZF_SET()) +#define cond_S ( NF_SET()) +#define cond_NS (!NF_SET()) +#define cond_P ( PF_SET()) +#define cond_NP (!PF_SET()) +#define cond_L (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0)) +#define cond_NL (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0)) +#define cond_LE (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0) || (ZF_SET())) +#define cond_NLE (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0) && (!ZF_SET())) + +#define opJ(condition) \ + static int opJ ## condition(uint32_t fetchdat) \ + { \ + int8_t offset = (int8_t)getbytef(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + return 1; \ + } \ + return 0; \ + } \ + \ + static int opJ ## condition ## _w(uint32_t fetchdat) \ + { \ + int16_t offset = (int16_t)getwordf(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + return 1; \ + } \ + return 0; \ + } \ + \ + static int opJ ## condition ## _l(uint32_t fetchdat) \ + { \ + uint32_t offset = getlong(); if (abrt) return 1; \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + return 1; \ + } \ + return 0; \ + } \ + +opJ(O) +opJ(NO) +opJ(B) +opJ(NB) +opJ(E) +opJ(NE) +opJ(BE) +opJ(NBE) +opJ(S) +opJ(NS) +opJ(P) +opJ(NP) +opJ(L) +opJ(NL) +opJ(LE) +opJ(NLE) + + + +static int opLOOPNE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (CX && !ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} +static int opLOOPNE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (ECX && !ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} + +static int opLOOPE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (CX && ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} +static int opLOOPE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (ECX && ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} + +static int opLOOP_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (CX) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} +static int opLOOP_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (ECX) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} + +static int opJCXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + if (!CX) + { + cpu_state.pc += offset; + CLOCK_CYCLES(4); + CPU_BLOCK_END(); + return 1; + } + return 0; +} +static int opJECXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + if (!ECX) + { + cpu_state.pc += offset; + CLOCK_CYCLES(4); + CPU_BLOCK_END(); + return 1; + } + return 0; +} + + +static int opJMP_r8(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} +static int opJMP_r16(uint32_t fetchdat) +{ + int16_t offset = (int16_t)getwordf(); + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} +static int opJMP_r32(uint32_t fetchdat) +{ + int32_t offset = (int32_t)getlong(); if (abrt) return 1; + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} + +static int opJMP_far_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint16_t seg = getword(); if (abrt) return 1; + uint32_t oxpc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, oxpc); + CPU_BLOCK_END(); + return 0; +} +static int opJMP_far_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint16_t seg = getword(); if (abrt) return 1; + uint32_t oxpc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, oxpc); + CPU_BLOCK_END(); + return 0; +} + +static int opCALL_r16(uint32_t fetchdat) +{ + int16_t addr = (int16_t)getwordf(); + PUSH_W(cpu_state.pc); + cpu_state.pc += addr; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} +static int opCALL_r32(uint32_t fetchdat) +{ + int32_t addr = getlong(); if (abrt) return 1; + PUSH_L(cpu_state.pc); + cpu_state.pc += addr; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} + +static int opRET_w(uint32_t fetchdat) +{ + uint16_t ret; + + ret = POP_W(); if (abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + return 0; +} +static int opRET_l(uint32_t fetchdat) +{ + uint32_t ret; + + ret = POP_L(); if (abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + return 0; +} + +static int opRET_w_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + uint16_t ret; + + ret = POP_W(); if (abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + return 0; +} +static int opRET_l_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + uint32_t ret; + + ret = POP_L(); if (abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + return 0; +} + diff --git a/src/x86_ops_misc.h b/src/x86_ops_misc.h new file mode 100644 index 000000000..d23421b89 --- /dev/null +++ b/src/x86_ops_misc.h @@ -0,0 +1,805 @@ +static int opCBW(uint32_t fetchdat) +{ + AH = (AL & 0x80) ? 0xff : 0; + CLOCK_CYCLES(3); + return 0; +} +static int opCWDE(uint32_t fetchdat) +{ + EAX = (AX & 0x8000) ? (0xffff0000 | AX) : AX; + CLOCK_CYCLES(3); + return 0; +} +static int opCWD(uint32_t fetchdat) +{ + DX = (AX & 0x8000) ? 0xFFFF : 0; + CLOCK_CYCLES(2); + return 0; +} +static int opCDQ(uint32_t fetchdat) +{ + EDX = (EAX & 0x80000000) ? 0xffffffff : 0; + CLOCK_CYCLES(2); + return 0; +} + +static int opNOP(uint32_t fetchdat) +{ + CLOCK_CYCLES((is486) ? 1 : 3); + return 0; +} + +static int opSETALC(uint32_t fetchdat) +{ + AL = (CF_SET()) ? 0xff : 0; + CLOCK_CYCLES(timing_rr); + return 0; +} + + + +static int opF6_a16(uint32_t fetchdat) +{ + int tempws, tempws2; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_16(fetchdat); + dst = geteab(); if (abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT b*/ + seteab(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x18: /*NEG b*/ + seteab(0 - dst); if (abrt) return 1; + setsub8(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(13); + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(14); + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags |= 0x8D5; /*Not a Cyrix*/ + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(is486 ? 16 : 14); + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags|=0x8D5; /*Not a Cyrix*/ + } + } + else + { +// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2); + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + break; + + default: + pclog("Bad F6 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF6_a32(uint32_t fetchdat) +{ + int tempws, tempws2; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_32(fetchdat); + dst = geteab(); if (abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT b*/ + seteab(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x18: /*NEG b*/ + seteab(0 - dst); if (abrt) return 1; + setsub8(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(13); + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(14); + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags |= 0x8D5; /*Not a Cyrix*/ + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(is486 ? 16 : 14); + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags|=0x8D5; /*Not a Cyrix*/ + } + } + else + { +// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2); + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + break; + + default: + pclog("Bad F6 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + + + +static int opF7_w_a16(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_16(fetchdat); + dst = geteaw(); if (abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + src = getword(); if (abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT w*/ + seteaw(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x18: /*NEG w*/ + seteaw(0 - dst); if (abrt) return 1; + setsub16(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(21); + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(22); + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); + x86_int(0); + return 1; + } + CLOCK_CYCLES(is486 ? 24 : 22); + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// pclog("IDIVw exception - %X / %08X = %X\n",tempws, dst, tempws2); + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF7_w_a32(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_32(fetchdat); + dst = geteaw(); if (abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + src = getword(); if (abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT w*/ + seteaw(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x18: /*NEG w*/ + seteaw(0 - dst); if (abrt) return 1; + setsub16(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(21); + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(22); + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); + x86_int(0); + return 1; + } + CLOCK_CYCLES(is486 ? 24 : 22); + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// pclog("IDIVw exception - %X / %08X = %X\n", tempws, dst, tempws2); + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + +static int opF7_l_a16(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_16(fetchdat); + dst = geteal(); if (abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + src = getlong(); if (abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT l*/ + seteal(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mml); + break; + case 0x18: /*NEG l*/ + seteal(0 - dst); if (abrt) return 1; + setsub32(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mml); + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + CLOCK_CYCLES(21); + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(38); + break; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF7_l_a32(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_32(fetchdat); + dst = geteal(); if (abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + src = getlong(); if (abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT l*/ + seteal(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mml); + break; + case 0x18: /*NEG l*/ + seteal(0 - dst); if (abrt) return 1; + setsub32(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mml); + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + CLOCK_CYCLES(21); + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(38); + break; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + + +static int opHLT(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + if (!((flags&I_FLAG) && pic_intpending)) + { + CLOCK_CYCLES_ALWAYS(100); + cpu_state.pc--; + } + else + CLOCK_CYCLES(5); + + CPU_BLOCK_END(); + + return 0; +} + + +static int opLOCK(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (abrt) return 0; + cpu_state.pc++; + + CLOCK_CYCLES(4); + return x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); +} + + + +static int opBOUND_w_a16(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + low = geteaw(); + high = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + + if (((int16_t)cpu_state.regs[reg].w < low) || ((int16_t)cpu_state.regs[reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + return 0; +} +static int opBOUND_w_a32(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + low = geteaw(); + high = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + + if (((int16_t)cpu_state.regs[reg].w < low) || ((int16_t)cpu_state.regs[reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + return 0; +} + +static int opBOUND_l_a16(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + low = geteal(); + high = readmeml(easeg, eaaddr + 4); if (abrt) return 1; + + if (((int32_t)cpu_state.regs[reg].l < low) || ((int32_t)cpu_state.regs[reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + return 0; +} +static int opBOUND_l_a32(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + low = geteal(); + high = readmeml(easeg, eaaddr + 4); if (abrt) return 1; + + if (((int32_t)cpu_state.regs[reg].l < low) || ((int32_t)cpu_state.regs[reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + return 0; +} + + +static int opCLTS(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't CLTS\n"); + x86gpf(NULL,0); + return 1; + } + cr0 &= ~8; + CLOCK_CYCLES(5); + return 0; +} + +static int opINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(1000); + CPU_BLOCK_END(); + return 0; +} +static int opWBINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(10000); + CPU_BLOCK_END(); + return 0; +} + + + +static int opLOADALL(uint32_t fetchdat) +{ + flags = (readmemw(0, 0x818) & 0xffd5) | 2; + flags_extract(); + cpu_state.pc = readmemw(0, 0x81A); + DS = readmemw(0, 0x81E); + SS = readmemw(0, 0x820); + CS = readmemw(0, 0x822); + ES = readmemw(0, 0x824); + DI = readmemw(0, 0x826); + SI = readmemw(0, 0x828); + BP = readmemw(0, 0x82A); + SP = readmemw(0, 0x82C); + BX = readmemw(0, 0x82E); + DX = readmemw(0, 0x830); + CX = readmemw(0, 0x832); + AX = readmemw(0, 0x834); + es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16); + cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16); + ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16); + ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16); + CLOCK_CYCLES(195); + return 0; +} + +static int set_segment_limit(x86seg *s, uint8_t segdat3) +{ + if ((s->access & 0x18) != 0x10 || !(s->access & (1 << 2))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat3 & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } +} + +static int loadall_load_segment(uint32_t addr, x86seg *s) +{ + uint32_t attrib = readmeml(0, addr); + uint32_t segdat3 = (attrib >> 16) & 0xff; + s->access = (attrib >> 8) & 0xff; + s->base = readmeml(0, addr + 4); + s->limit = readmeml(0, addr + 8); + + if (s == &_cs) use32 = (segdat3 & 0x40) ? 0x300 : 0; + if (s == &_ss) stack32 = (segdat3 & 0x40) ? 1 : 0; + + set_segment_limit(s, segdat3); +} + +static int opLOADALL386(uint32_t fetchdat) +{ + uint32_t la_addr = es + EDI; + + cr0 = readmeml(0, la_addr); + flags = readmemw(0, la_addr + 4); + eflags = readmemw(0, la_addr + 6); + flags_extract(); + cpu_state.pc = readmeml(0, la_addr + 8); + EDI = readmeml(0, la_addr + 0xC); + ESI = readmeml(0, la_addr + 0x10); + EBP = readmeml(0, la_addr + 0x14); + ESP = readmeml(0, la_addr + 0x18); + EBX = readmeml(0, la_addr + 0x1C); + EDX = readmeml(0, la_addr + 0x20); + ECX = readmeml(0, la_addr + 0x24); + EAX = readmeml(0, la_addr + 0x28); + dr[6] = readmeml(0, la_addr + 0x2C); + dr[7] = readmeml(0, la_addr + 0x30); + tr.seg = readmemw(0, la_addr + 0x34); + ldt.seg = readmemw(0, la_addr + 0x38); + GS = readmemw(0, la_addr + 0x3C); + FS = readmemw(0, la_addr + 0x40); + DS = readmemw(0, la_addr + 0x44); + SS = readmemw(0, la_addr + 0x48); + CS = readmemw(0, la_addr + 0x4C); + ES = readmemw(0, la_addr + 0x50); + + loadall_load_segment(la_addr + 0x54, &tr); + loadall_load_segment(la_addr + 0x60, &idt); + loadall_load_segment(la_addr + 0x6c, &gdt); + loadall_load_segment(la_addr + 0x78, &ldt); + loadall_load_segment(la_addr + 0x84, &_gs); + loadall_load_segment(la_addr + 0x90, &_fs); + loadall_load_segment(la_addr + 0x9c, &_ds); + loadall_load_segment(la_addr + 0xa8, &_ss); + loadall_load_segment(la_addr + 0xb4, &_cs); + loadall_load_segment(la_addr + 0xc0, &_es); + + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + + CLOCK_CYCLES(350); + return 0; +} + +static int opCPUID(uint32_t fetchdat) +{ + if (CPUID) + { + cpu_CPUID(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = oldpc; + x86illegal(); + return 1; +} + +static int opRDMSR(uint32_t fetchdat) +{ + if (cpu_hasMSR) + { + cpu_RDMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = oldpc; + x86illegal(); + return 1; +} + +static int opWRMSR(uint32_t fetchdat) +{ + if (cpu_hasMSR) + { + cpu_WRMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = oldpc; + x86illegal(); + return 1; +} + diff --git a/src/x86_ops_mmx.h b/src/x86_ops_mmx.h new file mode 100644 index 000000000..c83c0a145 --- /dev/null +++ b/src/x86_ops_mmx.h @@ -0,0 +1,48 @@ +#define SSATB(val) (((val) < -128) ? -128 : (((val) > 127) ? 127 : (val))) +#define SSATW(val) (((val) < -32768) ? -32768 : (((val) > 32767) ? 32767 : (val))) +#define USATB(val) (((val) < 0) ? 0 : (((val) > 255) ? 255 : (val))) +#define USATW(val) (((val) < 0) ? 0 : (((val) > 65535) ? 65535 : (val))) + +#define MMX_GETSRC() \ + if (mod == 3) \ + { \ + src = MM[rm]; \ + CLOCK_CYCLES(1); \ + } \ + else \ + { \ + src.q = readmemq(easeg, eaaddr); if (abrt) return 1; \ + CLOCK_CYCLES(2); \ + } + +#define MMX_ENTER() \ + if (!cpu_hasMMX) \ + { \ + cpu_state.pc = oldpc; \ + x86illegal(); \ + return 1; \ + } \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + x87_set_mmx() + +static int opEMMS(uint32_t fetchdat) +{ + if (!cpu_hasMMX) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + if (cr0 & 4) + { + x86_int(7); + return 1; + } + x87_emms(); + CLOCK_CYCLES(100); /*Guess*/ + return 0; +} diff --git a/src/x86_ops_mmx_arith.h b/src/x86_ops_mmx_arith.h new file mode 100644 index 000000000..14299621b --- /dev/null +++ b/src/x86_ops_mmx_arith.h @@ -0,0 +1,625 @@ +static int opPADDB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] += src.b[0]; + MM[reg].b[1] += src.b[1]; + MM[reg].b[2] += src.b[2]; + MM[reg].b[3] += src.b[3]; + MM[reg].b[4] += src.b[4]; + MM[reg].b[5] += src.b[5]; + MM[reg].b[6] += src.b[6]; + MM[reg].b[7] += src.b[7]; + + return 0; +} +static int opPADDB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] += src.b[0]; + MM[reg].b[1] += src.b[1]; + MM[reg].b[2] += src.b[2]; + MM[reg].b[3] += src.b[3]; + MM[reg].b[4] += src.b[4]; + MM[reg].b[5] += src.b[5]; + MM[reg].b[6] += src.b[6]; + MM[reg].b[7] += src.b[7]; + + return 0; +} + +static int opPADDW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] += src.w[0]; + MM[reg].w[1] += src.w[1]; + MM[reg].w[2] += src.w[2]; + MM[reg].w[3] += src.w[3]; + + return 0; +} +static int opPADDW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] += src.w[0]; + MM[reg].w[1] += src.w[1]; + MM[reg].w[2] += src.w[2]; + MM[reg].w[3] += src.w[3]; + + return 0; +} + +static int opPADDD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] += src.l[0]; + MM[reg].l[1] += src.l[1]; + + return 0; +} +static int opPADDD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] += src.l[0]; + MM[reg].l[1] += src.l[1]; + + return 0; +} + +static int opPADDSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] + src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] + src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] + src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] + src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] + src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] + src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] + src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] + src.sb[7]); + + return 0; +} +static int opPADDSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] + src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] + src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] + src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] + src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] + src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] + src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] + src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] + src.sb[7]); + + return 0; +} + +static int opPADDUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] + src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] + src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] + src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] + src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] + src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] + src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] + src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] + src.b[7]); + + return 0; +} +static int opPADDUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] + src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] + src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] + src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] + src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] + src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] + src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] + src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] + src.b[7]); + + return 0; +} + +static int opPADDSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] + src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] + src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] + src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] + src.sw[3]); + + return 0; +} +static int opPADDSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] + src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] + src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] + src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] + src.sw[3]); + + return 0; +} + +static int opPADDUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] + src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] + src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] + src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] + src.w[3]); + + return 0; +} +static int opPADDUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] + src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] + src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] + src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] + src.w[3]); + + return 0; +} + +static int opPMADDWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + if (MM[reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + MM[reg].l[0] = 0x80000000; + else + MM[reg].sl[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]); + + if (MM[reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + MM[reg].l[1] = 0x80000000; + else + MM[reg].sl[1] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} +static int opPMADDWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + if (MM[reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + MM[reg].l[0] = 0x80000000; + else + MM[reg].sl[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]); + + if (MM[reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + MM[reg].l[1] = 0x80000000; + else + MM[reg].sl[1] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} + + +static int opPMULLW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].w[0] *= MM[rm].w[0]; + MM[reg].w[1] *= MM[rm].w[1]; + MM[reg].w[2] *= MM[rm].w[2]; + MM[reg].w[3] *= MM[rm].w[3]; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] *= src.w[0]; + MM[reg].w[1] *= src.w[1]; + MM[reg].w[2] *= src.w[2]; + MM[reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULLW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].w[0] *= MM[rm].w[0]; + MM[reg].w[1] *= MM[rm].w[1]; + MM[reg].w[2] *= MM[rm].w[2]; + MM[reg].w[3] *= MM[rm].w[3]; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] *= src.w[0]; + MM[reg].w[1] *= src.w[1]; + MM[reg].w[2] *= src.w[2]; + MM[reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPMULHW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)MM[rm].sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)MM[rm].sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)MM[rm].sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)MM[rm].sw[3]) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULHW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)MM[rm].sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)MM[rm].sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)MM[rm].sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)MM[rm].sw[3]) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPSUBB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] -= src.b[0]; + MM[reg].b[1] -= src.b[1]; + MM[reg].b[2] -= src.b[2]; + MM[reg].b[3] -= src.b[3]; + MM[reg].b[4] -= src.b[4]; + MM[reg].b[5] -= src.b[5]; + MM[reg].b[6] -= src.b[6]; + MM[reg].b[7] -= src.b[7]; + + return 0; +} +static int opPSUBB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] -= src.b[0]; + MM[reg].b[1] -= src.b[1]; + MM[reg].b[2] -= src.b[2]; + MM[reg].b[3] -= src.b[3]; + MM[reg].b[4] -= src.b[4]; + MM[reg].b[5] -= src.b[5]; + MM[reg].b[6] -= src.b[6]; + MM[reg].b[7] -= src.b[7]; + + return 0; +} + +static int opPSUBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] -= src.w[0]; + MM[reg].w[1] -= src.w[1]; + MM[reg].w[2] -= src.w[2]; + MM[reg].w[3] -= src.w[3]; + + return 0; +} +static int opPSUBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] -= src.w[0]; + MM[reg].w[1] -= src.w[1]; + MM[reg].w[2] -= src.w[2]; + MM[reg].w[3] -= src.w[3]; + + return 0; +} + +static int opPSUBD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] -= src.l[0]; + MM[reg].l[1] -= src.l[1]; + + return 0; +} +static int opPSUBD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] -= src.l[0]; + MM[reg].l[1] -= src.l[1]; + + return 0; +} + +static int opPSUBSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] - src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] - src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] - src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] - src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] - src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] - src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] - src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] - src.sb[7]); + + return 0; +} +static int opPSUBSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] - src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] - src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] - src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] - src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] - src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] - src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] - src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] - src.sb[7]); + + return 0; +} + +static int opPSUBUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] - src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] - src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] - src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] - src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] - src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] - src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] - src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] - src.b[7]); + + return 0; +} +static int opPSUBUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] - src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] - src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] - src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] - src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] - src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] - src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] - src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] - src.b[7]); + + return 0; +} + +static int opPSUBSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] - src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] - src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] - src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] - src.sw[3]); + + return 0; +} +static int opPSUBSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] - src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] - src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] - src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] - src.sw[3]); + + return 0; +} + +static int opPSUBUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] - src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] - src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] - src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] - src.w[3]); + + return 0; +} +static int opPSUBUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] - src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] - src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] - src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] - src.w[3]); + + return 0; +} diff --git a/src/x86_ops_mmx_cmp.h b/src/x86_ops_mmx_cmp.h new file mode 100644 index 000000000..5fe3fc5ab --- /dev/null +++ b/src/x86_ops_mmx_cmp.h @@ -0,0 +1,205 @@ +static int opPCMPEQB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].b[0] == src.b[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].b[1] == src.b[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].b[2] == src.b[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].b[3] == src.b[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].b[4] == src.b[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].b[5] == src.b[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].b[6] == src.b[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPEQB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].b[0] == src.b[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].b[1] == src.b[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].b[2] == src.b[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].b[3] == src.b[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].b[4] == src.b[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].b[5] == src.b[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].b[6] == src.b[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPGTB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].sb[0] > src.sb[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].sb[1] > src.sb[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].sb[2] > src.sb[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].sb[3] > src.sb[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].sb[4] > src.sb[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].sb[5] > src.sb[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].sb[6] > src.sb[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPGTB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].sb[0] > src.sb[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].sb[1] > src.sb[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].sb[2] > src.sb[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].sb[3] > src.sb[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].sb[4] > src.sb[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].sb[5] > src.sb[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].sb[6] > src.sb[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPEQW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].w[0] == src.w[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].w[1] == src.w[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].w[2] == src.w[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPEQW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].w[0] == src.w[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].w[1] == src.w[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].w[2] == src.w[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPGTW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].sw[0] > src.sw[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].sw[1] > src.sw[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].sw[2] > src.sw[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPGTW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].sw[0] > src.sw[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].sw[1] > src.sw[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].sw[2] > src.sw[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPEQD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].l[0] == src.l[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPEQD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].l[0] == src.l[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} + +static int opPCMPGTD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPGTD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} diff --git a/src/x86_ops_mmx_logic.h b/src/x86_ops_mmx_logic.h new file mode 100644 index 000000000..f6bb880b7 --- /dev/null +++ b/src/x86_ops_mmx_logic.h @@ -0,0 +1,91 @@ +static int opPAND_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q &= src.q; + return 0; +} +static int opPAND_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q &= src.q; + return 0; +} + +static int opPANDN_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q = ~MM[reg].q & src.q; + return 0; +} +static int opPANDN_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q = ~MM[reg].q & src.q; + return 0; +} + +static int opPOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q |= src.q; + return 0; +} +static int opPOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q |= src.q; + return 0; +} + +static int opPXOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q ^= src.q; + return 0; +} +static int opPXOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q ^= src.q; + return 0; +} diff --git a/src/x86_ops_mmx_mov.h b/src/x86_ops_mmx_mov.h new file mode 100644 index 000000000..4779ff6a3 --- /dev/null +++ b/src/x86_ops_mmx_mov.h @@ -0,0 +1,161 @@ +static int opMOVD_l_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].l[0] = cpu_state.regs[rm].l; + MM[reg].l[1] = 0; + CLOCK_CYCLES(1); + } + else + { + uint32_t dst; + + dst = readmeml(easeg, eaaddr); if (abrt) return 1; + MM[reg].l[0] = dst; + MM[reg].l[1] = 0; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_l_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].l[0] = cpu_state.regs[rm].l; + MM[reg].l[1] = 0; + CLOCK_CYCLES(1); + } + else + { + uint32_t dst; + + dst = readmeml(easeg, eaaddr); if (abrt) return 1; + MM[reg].l[0] = dst; + MM[reg].l[1] = 0; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVD_mm_l_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].l = MM[reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 3); + writememl(easeg, eaaddr, MM[reg].l[0]); if (abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_mm_l_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].l = MM[reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 3); + writememl(easeg, eaaddr, MM[reg].l[0]); if (abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVQ_q_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].q = MM[rm].q; + CLOCK_CYCLES(1); + } + else + { + uint64_t dst; + + dst = readmemq(easeg, eaaddr); if (abrt) return 1; + MM[reg].q = dst; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVQ_q_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].q = MM[rm].q; + CLOCK_CYCLES(1); + } + else + { + uint64_t dst; + + dst = readmemq(easeg, eaaddr); if (abrt) return 1; + MM[reg].q = dst; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVQ_mm_q_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[rm].q = MM[reg].q; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 7); + writememq(easeg, eaaddr, MM[reg].l[0]); if (abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVQ_mm_q_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[rm].q = MM[reg].q; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 7); + writememq(easeg, eaaddr, MM[reg].q); if (abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} diff --git a/src/x86_ops_mmx_pack.h b/src/x86_ops_mmx_pack.h new file mode 100644 index 000000000..e9b84fbd3 --- /dev/null +++ b/src/x86_ops_mmx_pack.h @@ -0,0 +1,324 @@ +static int opPUNPCKLDQ_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].l[1] = MM[rm].l[0]; + CLOCK_CYCLES(1); + } + else + { + uint32_t src; + + src = readmeml(easeg, eaaddr); if (abrt) return 0; + MM[reg].l[1] = src; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opPUNPCKLDQ_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].l[1] = MM[rm].l[0]; + CLOCK_CYCLES(1); + } + else + { + uint32_t src; + + src = readmeml(easeg, eaaddr); if (abrt) return 0; + MM[reg].l[1] = src; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPUNPCKHDQ_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = MM[reg].l[1]; + MM[reg].l[1] = src.l[1]; + + return 0; +} +static int opPUNPCKHDQ_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = MM[reg].l[1]; + MM[reg].l[1] = src.l[1]; + + return 0; +} + +static int opPUNPCKLBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[7] = src.b[3]; + MM[reg].b[6] = MM[reg].b[3]; + MM[reg].b[5] = src.b[2]; + MM[reg].b[4] = MM[reg].b[2]; + MM[reg].b[3] = src.b[1]; + MM[reg].b[2] = MM[reg].b[1]; + MM[reg].b[1] = src.b[0]; + MM[reg].b[0] = MM[reg].b[0]; + + return 0; +} +static int opPUNPCKLBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[7] = src.b[3]; + MM[reg].b[6] = MM[reg].b[3]; + MM[reg].b[5] = src.b[2]; + MM[reg].b[4] = MM[reg].b[2]; + MM[reg].b[3] = src.b[1]; + MM[reg].b[2] = MM[reg].b[1]; + MM[reg].b[1] = src.b[0]; + MM[reg].b[0] = MM[reg].b[0]; + + return 0; +} + +static int opPUNPCKHBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = MM[reg].b[4]; + MM[reg].b[1] = src.b[4]; + MM[reg].b[2] = MM[reg].b[5]; + MM[reg].b[3] = src.b[5]; + MM[reg].b[4] = MM[reg].b[6]; + MM[reg].b[5] = src.b[6]; + MM[reg].b[6] = MM[reg].b[7]; + MM[reg].b[7] = src.b[7]; + + return 0; +} +static int opPUNPCKHBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = MM[reg].b[4]; + MM[reg].b[1] = src.b[4]; + MM[reg].b[2] = MM[reg].b[5]; + MM[reg].b[3] = src.b[5]; + MM[reg].b[4] = MM[reg].b[6]; + MM[reg].b[5] = src.b[6]; + MM[reg].b[6] = MM[reg].b[7]; + MM[reg].b[7] = src.b[7]; + + return 0; +} + +static int opPUNPCKLWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[3] = src.w[1]; + MM[reg].w[2] = MM[reg].w[1]; + MM[reg].w[1] = src.w[0]; + MM[reg].w[0] = MM[reg].w[0]; + + return 0; +} +static int opPUNPCKLWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[3] = src.w[1]; + MM[reg].w[2] = MM[reg].w[1]; + MM[reg].w[1] = src.w[0]; + MM[reg].w[0] = MM[reg].w[0]; + + return 0; +} + +static int opPUNPCKHWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = MM[reg].w[2]; + MM[reg].w[1] = src.w[2]; + MM[reg].w[2] = MM[reg].w[3]; + MM[reg].w[3] = src.w[3]; + + return 0; +} +static int opPUNPCKHWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = MM[reg].w[2]; + MM[reg].w[1] = src.w[2]; + MM[reg].w[2] = MM[reg].w[3]; + MM[reg].w[3] = src.w[3]; + + return 0; +} + +static int opPACKSSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sb[0] = SSATB(dst.sw[0]); + MM[reg].sb[1] = SSATB(dst.sw[1]); + MM[reg].sb[2] = SSATB(dst.sw[2]); + MM[reg].sb[3] = SSATB(dst.sw[3]); + MM[reg].sb[4] = SSATB(src.sw[0]); + MM[reg].sb[5] = SSATB(src.sw[1]); + MM[reg].sb[6] = SSATB(src.sw[2]); + MM[reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} +static int opPACKSSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sb[0] = SSATB(dst.sw[0]); + MM[reg].sb[1] = SSATB(dst.sw[1]); + MM[reg].sb[2] = SSATB(dst.sw[2]); + MM[reg].sb[3] = SSATB(dst.sw[3]); + MM[reg].sb[4] = SSATB(src.sw[0]); + MM[reg].sb[5] = SSATB(src.sw[1]); + MM[reg].sb[6] = SSATB(src.sw[2]); + MM[reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} + +static int opPACKUSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].b[0] = USATB(dst.sw[0]); + MM[reg].b[1] = USATB(dst.sw[1]); + MM[reg].b[2] = USATB(dst.sw[2]); + MM[reg].b[3] = USATB(dst.sw[3]); + MM[reg].b[4] = USATB(src.sw[0]); + MM[reg].b[5] = USATB(src.sw[1]); + MM[reg].b[6] = USATB(src.sw[2]); + MM[reg].b[7] = USATB(src.sw[3]); + + return 0; +} +static int opPACKUSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].b[0] = USATB(dst.sw[0]); + MM[reg].b[1] = USATB(dst.sw[1]); + MM[reg].b[2] = USATB(dst.sw[2]); + MM[reg].b[3] = USATB(dst.sw[3]); + MM[reg].b[4] = USATB(src.sw[0]); + MM[reg].b[5] = USATB(src.sw[1]); + MM[reg].b[6] = USATB(src.sw[2]); + MM[reg].b[7] = USATB(src.sw[3]); + + return 0; +} + +static int opPACKSSDW_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sw[0] = SSATW(dst.sl[0]); + MM[reg].sw[1] = SSATW(dst.sl[1]); + MM[reg].sw[2] = SSATW(src.sl[0]); + MM[reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} +static int opPACKSSDW_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sw[0] = SSATW(dst.sl[0]); + MM[reg].sw[1] = SSATW(dst.sl[1]); + MM[reg].sw[2] = SSATW(src.sl[0]); + MM[reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} diff --git a/src/x86_ops_mmx_shift.h b/src/x86_ops_mmx_shift.h new file mode 100644 index 000000000..760998a7d --- /dev/null +++ b/src/x86_ops_mmx_shift.h @@ -0,0 +1,452 @@ +#define MMX_GETSHIFT() \ + if (mod == 3) \ + { \ + shift = MM[rm].b[0]; \ + CLOCK_CYCLES(1); \ + } \ + else \ + { \ + shift = readmemb(easeg, eaaddr); if (abrt) return 0; \ + CLOCK_CYCLES(2); \ + } + +static int opPSxxW_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] >>= shift; + MM[reg].w[1] >>= shift; + MM[reg].w[2] >>= shift; + MM[reg].w[3] >>= shift; + } + break; + case 0x20: /*PSRAW*/ + if (shift > 15) + shift = 15; + MM[reg].sw[0] >>= shift; + MM[reg].sw[1] >>= shift; + MM[reg].sw[2] >>= shift; + MM[reg].sw[3] >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] <<= shift; + MM[reg].w[1] <<= shift; + MM[reg].w[2] <<= shift; + MM[reg].w[3] <<= shift; + } + break; + default: + pclog("Bad PSxxW (0F 71) instruction %02X\n", op); + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] <<= shift; + MM[reg].w[1] <<= shift; + MM[reg].w[2] <<= shift; + MM[reg].w[3] <<= shift; + } + + return 0; +} +static int opPSLLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] <<= shift; + MM[reg].w[1] <<= shift; + MM[reg].w[2] <<= shift; + MM[reg].w[3] <<= shift; + } + + return 0; +} + +static int opPSRLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] >>= shift; + MM[reg].w[1] >>= shift; + MM[reg].w[2] >>= shift; + MM[reg].w[3] >>= shift; + } + + return 0; +} +static int opPSRLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] >>= shift; + MM[reg].w[1] >>= shift; + MM[reg].w[2] >>= shift; + MM[reg].w[3] >>= shift; + } + + return 0; +} + +static int opPSRAW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + MM[reg].sw[0] >>= shift; + MM[reg].sw[1] >>= shift; + MM[reg].sw[2] >>= shift; + MM[reg].sw[3] >>= shift; + + return 0; +} +static int opPSRAW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + MM[reg].sw[0] >>= shift; + MM[reg].sw[1] >>= shift; + MM[reg].sw[2] >>= shift; + MM[reg].sw[3] >>= shift; + + return 0; +} + +static int opPSxxD_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLD*/ + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] >>= shift; + MM[reg].l[1] >>= shift; + } + break; + case 0x20: /*PSRAD*/ + if (shift > 31) + shift = 31; + MM[reg].sl[0] >>= shift; + MM[reg].sl[1] >>= shift; + break; + case 0x30: /*PSLLD*/ + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] <<= shift; + MM[reg].l[1] <<= shift; + } + break; + default: + pclog("Bad PSxxD (0F 72) instruction %02X\n", op); + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] <<= shift; + MM[reg].l[1] <<= shift; + } + + return 0; +} +static int opPSLLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] <<= shift; + MM[reg].l[1] <<= shift; + } + + return 0; +} + +static int opPSRLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] >>= shift; + MM[reg].l[1] >>= shift; + } + + return 0; +} +static int opPSRLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] >>= shift; + MM[reg].l[1] >>= shift; + } + + return 0; +} + +static int opPSRAD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + MM[reg].sl[0] >>= shift; + MM[reg].sl[1] >>= shift; + + return 0; +} +static int opPSRAD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + MM[reg].sl[0] >>= shift; + MM[reg].sl[1] >>= shift; + + return 0; +} + +static int opPSxxQ_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q >>= shift; + break; + case 0x20: /*PSRAW*/ + if (shift > 63) + shift = 63; + MM[reg].sq >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q <<= shift; + break; + default: + pclog("Bad PSxxQ (0F 73) instruction %02X\n", op); + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q <<= shift; + + return 0; +} +static int opPSLLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q <<= shift; + + return 0; +} + +static int opPSRLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q >>= shift; + + return 0; +} +static int opPSRLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q >>= shift; + + return 0; +} diff --git a/src/x86_ops_mov.h b/src/x86_ops_mov.h new file mode 100644 index 000000000..d75f93861 --- /dev/null +++ b/src/x86_ops_mov.h @@ -0,0 +1,655 @@ +static int opMOV_AL_imm(uint32_t fetchdat) +{ + AL = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_AH_imm(uint32_t fetchdat) +{ + AH = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_BL_imm(uint32_t fetchdat) +{ + BL = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_BH_imm(uint32_t fetchdat) +{ + BH = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_CL_imm(uint32_t fetchdat) +{ + CL = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_CH_imm(uint32_t fetchdat) +{ + CH = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_DL_imm(uint32_t fetchdat) +{ + DL = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_DH_imm(uint32_t fetchdat) +{ + DH = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opMOV_AX_imm(uint32_t fetchdat) +{ + AX = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_BX_imm(uint32_t fetchdat) +{ + BX = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_CX_imm(uint32_t fetchdat) +{ + CX = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_DX_imm(uint32_t fetchdat) +{ + DX = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_SI_imm(uint32_t fetchdat) +{ + SI = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_DI_imm(uint32_t fetchdat) +{ + DI = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_BP_imm(uint32_t fetchdat) +{ + BP = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_SP_imm(uint32_t fetchdat) +{ + SP = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opMOV_EAX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EAX = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_EBX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EBX = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_ECX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + ECX = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_EDX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EDX = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_ESI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + ESI = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_EDI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EDI = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_EBP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EBP = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_ESP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + ESP = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opMOV_b_imm_a16(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_16(fetchdat); + temp = readmemb(cs,cpu_state.pc); cpu_state.pc++; if (abrt) return 1; + CHECK_WRITE(ea_seg, eaaddr, eaaddr); + seteab(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} +static int opMOV_b_imm_a32(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_32(fetchdat); + temp = getbyte(); if (abrt) return 1; + seteab(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} + +static int opMOV_w_imm_a16(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_16(fetchdat); + temp = getword(); if (abrt) return 1; + seteaw(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} +static int opMOV_w_imm_a32(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_32(fetchdat); + temp = getword(); if (abrt) return 1; + seteaw(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} +static int opMOV_l_imm_a16(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_16(fetchdat); + temp = getlong(); if (abrt) return 1; + seteal(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} +static int opMOV_l_imm_a32(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_32(fetchdat); + temp = getlong(); if (abrt) return 1; + seteal(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} + + +static int opMOV_AL_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint8_t temp = readmemb(ea_seg->base, addr); if (abrt) return 1; + AL = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_AL_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint8_t temp = readmemb(ea_seg->base, addr); if (abrt) return 1; + AL = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_AX_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint16_t temp = readmemw(ea_seg->base, addr); if (abrt) return 1; + AX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_AX_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint16_t temp = readmemw(ea_seg->base, addr); if (abrt) return 1; + AX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_EAX_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint32_t temp = readmeml(ea_seg->base, addr); if (abrt) return 1; + EAX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_EAX_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint32_t temp = readmeml(ea_seg->base, addr); if (abrt) return 1; + EAX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} + +static int opMOV_a16_AL(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + writememb(ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a32_AL(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + writememb(ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a16_AX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + writememw(ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a32_AX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); if (abrt) return 1; + writememw(ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a16_EAX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + writememl(ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a32_EAX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); if (abrt) return 1; + writememl(ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} + + +static int opLEA_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + cpu_state.regs[reg].w = eaaddr; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opLEA_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + cpu_state.regs[reg].w = eaaddr; + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opLEA_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + cpu_state.regs[reg].l = eaaddr & 0xffff; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opLEA_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + cpu_state.regs[reg].l = eaaddr; + CLOCK_CYCLES(timing_rr); + return 0; +} + + + +static int opXLAT_a16(uint32_t fetchdat) +{ + uint32_t addr = (BX + AL)&0xFFFF; + uint8_t temp = readmemb(ea_seg->base, addr); if (abrt) return 1; + AL = temp; + CLOCK_CYCLES(5); + return 0; +} +static int opXLAT_a32(uint32_t fetchdat) +{ + uint32_t addr = EBX + AL; + uint8_t temp = readmemb(ea_seg->base, addr); if (abrt) return 1; + AL = temp; + CLOCK_CYCLES(5); + return 0; +} + +static int opMOV_b_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + setr8(rm, getr8(reg)); + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr); + seteab(getr8(reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_b_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + setr8(rm, getr8(reg)); + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr); + seteab(getr8(reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_w_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].w = cpu_state.regs[reg].w; + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr+1); + seteaw(cpu_state.regs[reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_w_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].w = cpu_state.regs[reg].w; + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr+1); + seteaw(cpu_state.regs[reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_l_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].l = cpu_state.regs[reg].l; + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr+3); + seteal(cpu_state.regs[reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_l_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].l = cpu_state.regs[reg].l; + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr+3); + seteal(cpu_state.regs[reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} + +static int opMOV_r_b_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + setr8(reg, getr8(rm)); + CLOCK_CYCLES(timing_rr); + } + else + { + uint8_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr); + temp = geteab(); if (abrt) return 1; + setr8(reg, temp); + CLOCK_CYCLES(is486 ? 1 : 4); + } + return 0; +} +static int opMOV_r_b_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + setr8(reg, getr8(rm)); + CLOCK_CYCLES(timing_rr); + } + else + { + uint8_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr); + temp = geteab(); if (abrt) return 1; + setr8(reg, temp); + CLOCK_CYCLES(is486 ? 1 : 4); + } + return 0; +} +static int opMOV_r_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[reg].w = cpu_state.regs[rm].w; + CLOCK_CYCLES(timing_rr); + } + else + { + uint16_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr+1); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + } + return 0; +} +static int opMOV_r_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[reg].w = cpu_state.regs[rm].w; + CLOCK_CYCLES(timing_rr); + } + else + { + uint16_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr+1); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + } + return 0; +} +static int opMOV_r_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[reg].l = cpu_state.regs[rm].l; + CLOCK_CYCLES(timing_rr); + } + else + { + uint32_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr+3); + temp = geteal(); if (abrt) return 1; + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + } + return 0; +} +static int opMOV_r_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[reg].l = cpu_state.regs[rm].l; + CLOCK_CYCLES(timing_rr); + } + else + { + uint32_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr+3); + temp = geteal(); if (abrt) return 1; + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + } + return 0; +} + +#define opCMOV(condition) \ + static int opCMOV ## condition ## _w_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (mod == 3) \ + cpu_state.regs[reg].w = cpu_state.regs[rm].w; \ + else \ + { \ + uint16_t temp; \ + CHECK_READ(ea_seg, eaaddr, eaaddr+1); \ + temp = geteaw(); if (abrt) return 1; \ + cpu_state.regs[reg].w = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _w_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (mod == 3) \ + cpu_state.regs[reg].w = cpu_state.regs[rm].w; \ + else \ + { \ + uint16_t temp; \ + CHECK_READ(ea_seg, eaaddr, eaaddr+1); \ + temp = geteaw(); if (abrt) return 1; \ + cpu_state.regs[reg].w = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (mod == 3) \ + cpu_state.regs[reg].l = cpu_state.regs[rm].l; \ + else \ + { \ + uint32_t temp; \ + CHECK_READ(ea_seg, eaaddr, eaaddr+3); \ + temp = geteal(); if (abrt) return 1; \ + cpu_state.regs[reg].l = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (mod == 3) \ + cpu_state.regs[reg].l = cpu_state.regs[rm].l; \ + else \ + { \ + uint32_t temp; \ + CHECK_READ(ea_seg, eaaddr, eaaddr+3); \ + temp = geteal(); if (abrt) return 1; \ + cpu_state.regs[reg].l = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } + +opCMOV(O) +opCMOV(NO) +opCMOV(B) +opCMOV(NB) +opCMOV(E) +opCMOV(NE) +opCMOV(BE) +opCMOV(NBE) +opCMOV(S) +opCMOV(NS) +opCMOV(P) +opCMOV(NP) +opCMOV(L) +opCMOV(NL) +opCMOV(LE) +opCMOV(NLE) diff --git a/src/x86_ops_mov_ctrl.h b/src/x86_ops_mov_ctrl.h new file mode 100644 index 000000000..633173417 --- /dev/null +++ b/src/x86_ops_mov_ctrl.h @@ -0,0 +1,268 @@ +static int opMOV_r_CRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from CRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + switch (reg) + { + case 0: + cpu_state.regs[rm].l = cr0; + if (is486) + cpu_state.regs[rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[rm].l = cr2; + break; + case 3: + cpu_state.regs[rm].l = cr3; + break; + case 4: + if (cpu_hasCR4) + { + cpu_state.regs[rm].l = cr4; + break; + } + default: + pclog("Bad read of CR%i %i\n",rmdat&7,reg); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_r_CRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from CRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + switch (reg) + { + case 0: + cpu_state.regs[rm].l = cr0; + if (is486) + cpu_state.regs[rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[rm].l = cr2; + break; + case 3: + cpu_state.regs[rm].l = cr3; + break; + case 4: + if (cpu_hasCR4) + { + cpu_state.regs[rm].l = cr4; + break; + } + default: + pclog("Bad read of CR%i %i\n",rmdat&7,reg); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + return 0; +} + +static int opMOV_r_DRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[rm].l = dr[reg]; + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_r_DRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[rm].l = dr[reg]; + CLOCK_CYCLES(6); + return 0; +} + +static int opMOV_CRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load CRx\n"); + x86gpf(NULL,0); + return 1; + } + fetch_ea_16(fetchdat); + switch (reg) + { + case 0: + if ((cpu_state.regs[rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + break; + case 2: + cr2 = cpu_state.regs[rm].l; + break; + case 3: + cr3 = cpu_state.regs[rm].l; + flushmmucache(); + break; + case 4: + if (cpu_hasCR4) + { + cr4 = cpu_state.regs[rm].l & cpu_CR4_mask; + break; + } + + default: + pclog("Bad load CR%i\n", reg); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + return 0; +} +static int opMOV_CRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load CRx\n"); + x86gpf(NULL,0); + return 1; + } + fetch_ea_32(fetchdat); + switch (reg) + { + case 0: + if ((cpu_state.regs[rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + break; + case 2: + cr2 = cpu_state.regs[rm].l; + break; + case 3: + cr3 = cpu_state.regs[rm].l; + flushmmucache(); + break; + case 4: + if (cpu_hasCR4) + { + cr4 = cpu_state.regs[rm].l & cpu_CR4_mask; + break; + } + + default: + pclog("Bad load CR%i\n", reg); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + return 0; +} + +static int opMOV_DRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[reg] = cpu_state.regs[rm].l; + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_DRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[reg] = cpu_state.regs[rm].l; + CLOCK_CYCLES(6); + return 0; +} + +static int opMOV_r_TRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[rm].l = 0; + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_r_TRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[rm].l = 0; + CLOCK_CYCLES(6); + return 0; +} + +static int opMOV_TRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_TRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + return 0; +} + diff --git a/src/x86_ops_mov_seg.h b/src/x86_ops_mov_seg.h new file mode 100644 index 000000000..d728423a6 --- /dev/null +++ b/src/x86_ops_mov_seg.h @@ -0,0 +1,394 @@ +static int opMOV_w_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 3); + return abrt; +} +static int opMOV_w_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 3); + return abrt; +} + +static int opMOV_l_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (mod == 3) cpu_state.regs[rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (mod == 3) cpu_state.regs[rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (mod == 3) cpu_state.regs[rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (mod == 3) cpu_state.regs[rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (mod == 3) cpu_state.regs[rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (mod == 3) cpu_state.regs[rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 3); + return abrt; +} +static int opMOV_l_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (mod == 3) cpu_state.regs[rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (mod == 3) cpu_state.regs[rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (mod == 3) cpu_state.regs[rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (mod == 3) cpu_state.regs[rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (mod == 3) cpu_state.regs[rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (mod == 3) cpu_state.regs[rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 3); + return abrt; +} + +static int opMOV_seg_w_a16(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_16(fetchdat); + + new_seg=geteaw(); if (abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &_ds); + break; + case 0x10: /*SS*/ + loadseg(new_seg, &_ss); + if (abrt) return 1; + oldpc = cpu_state.pc; + op32 = use32; + ssegs = 0; + ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &_gs); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 5); + return abrt; +} +static int opMOV_seg_w_a32(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_32(fetchdat); + + new_seg=geteaw(); if (abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &_ds); + break; + case 0x10: /*SS*/ + loadseg(new_seg, &_ss); + if (abrt) return 1; + oldpc = cpu_state.pc; + op32 = use32; + ssegs = 0; + ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &_gs); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 5); + return abrt; +} + + +static int opLDS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + loadseg(seg, &_ds); if (abrt) return 1; + cpu_state.regs[reg].w = addr; + + CLOCK_CYCLES(7); + return 0; +} +static int opLDS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + loadseg(seg, &_ds); if (abrt) return 1; + cpu_state.regs[reg].w = addr; + + CLOCK_CYCLES(7); + return 0; +} +static int opLDS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + loadseg(seg, &_ds); if (abrt) return 1; + cpu_state.regs[reg].l = addr; + + CLOCK_CYCLES(7); + return 0; +} +static int opLDS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + loadseg(seg, &_ds); if (abrt) return 1; + cpu_state.regs[reg].l = addr; + + CLOCK_CYCLES(7); + return 0; +} + +static int opLSS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + loadseg(seg, &_ss); if (abrt) return 1; + cpu_state.regs[reg].w = addr; + + CLOCK_CYCLES(7); + return 1; +} +static int opLSS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + loadseg(seg, &_ss); if (abrt) return 1; + cpu_state.regs[reg].w = addr; + + CLOCK_CYCLES(7); + return 1; +} +static int opLSS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + loadseg(seg, &_ss); if (abrt) return 1; + cpu_state.regs[reg].l = addr; + + CLOCK_CYCLES(7); + return 1; +} +static int opLSS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + loadseg(seg, &_ss); if (abrt) return 1; + cpu_state.regs[reg].l = addr; + + CLOCK_CYCLES(7); + return 1; +} + +#define opLsel(name, sel) \ + static int opL ## name ## _w_a16(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_16(fetchdat); \ + ILLEGAL_ON(mod == 3); \ + addr = readmemw(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; \ + loadseg(seg, &sel); if (abrt) return 1; \ + cpu_state.regs[reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + return 0; \ + } \ + \ + static int opL ## name ## _w_a32(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_32(fetchdat); \ + ILLEGAL_ON(mod == 3); \ + addr = readmemw(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; \ + loadseg(seg, &sel); if (abrt) return 1; \ + cpu_state.regs[reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a16(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_16(fetchdat); \ + ILLEGAL_ON(mod == 3); \ + addr = readmeml(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; \ + loadseg(seg, &sel); if (abrt) return 1; \ + cpu_state.regs[reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a32(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_32(fetchdat); \ + ILLEGAL_ON(mod == 3); \ + addr = readmeml(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; \ + loadseg(seg, &sel); if (abrt) return 1; \ + cpu_state.regs[reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + return 0; \ + } + +opLsel(ES, _es) +opLsel(FS, _fs) +opLsel(GS, _gs) diff --git a/src/x86_ops_movx.h b/src/x86_ops_movx.h new file mode 100644 index 000000000..ac5ff45e1 --- /dev/null +++ b/src/x86_ops_movx.h @@ -0,0 +1,167 @@ +static int opMOVZX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].w = (uint16_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].w = (uint16_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_w_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_w_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + return 0; +} + +static int opMOVSX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].w = (uint16_t)temp; + if (temp & 0x80) + cpu_state.regs[reg].w |= 0xff00; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].w = (uint16_t)temp; + if (temp & 0x80) + cpu_state.regs[reg].w |= 0xff00; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + if (temp & 0x80) + cpu_state.regs[reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + if (temp & 0x80) + cpu_state.regs[reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + if (temp & 0x8000) + cpu_state.regs[reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + if (temp & 0x8000) + cpu_state.regs[reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + return 0; +} diff --git a/src/x86_ops_msr.h b/src/x86_ops_msr.h new file mode 100644 index 000000000..3d8cc07f8 --- /dev/null +++ b/src/x86_ops_msr.h @@ -0,0 +1,30 @@ +static int opRDTSC(uint32_t fetchdat) +{ + if (!cpu_hasrdtsc) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + if ((cr4 & CR4_TSD) && CPL) + { + x86gpf("RDTSC when TSD set and CPL != 0", 0); + return 1; + } + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + CLOCK_CYCLES(1); + return 0; +} + +static int opRDPMC(uint32_t fetchdat) +{ + if (ECX > 1 || (!(cr4 & CR4_PCE) && (cr0 & 1) && CPL)) + { + x86gpf("RDPMC not allowed", 0); + return 1; + } + EAX = EDX = 0; + CLOCK_CYCLES(1); + return 0; +} diff --git a/src/x86_ops_mul.h b/src/x86_ops_mul.h new file mode 100644 index 000000000..b64276789 --- /dev/null +++ b/src/x86_ops_mul.h @@ -0,0 +1,222 @@ +static int opIMUL_w_iw_a16(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + + tempw = geteaw(); if (abrt) return 1; + tempw2 = getword(); if (abrt) return 1; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].w = templ & 0xffff; + + CLOCK_CYCLES((mod == 3) ? 14 : 17); + return 0; +} +static int opIMUL_w_iw_a32(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + + tempw = geteaw(); if (abrt) return 1; + tempw2 = getword(); if (abrt) return 1; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].w = templ & 0xffff; + + CLOCK_CYCLES((mod == 3) ? 14 : 17); + return 0; +} + +static int opIMUL_l_il_a16(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + + templ = geteal(); if (abrt) return 1; + templ2 = getlong(); if (abrt) return 1; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(25); + return 0; +} +static int opIMUL_l_il_a32(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + + templ = geteal(); if (abrt) return 1; + templ2 = getlong(); if (abrt) return 1; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(25); + return 0; +} + +static int opIMUL_w_ib_a16(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + + tempw = geteaw(); if (abrt) return 1; + tempw2 = getbyte(); if (abrt) return 1; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].w = templ & 0xffff; + + CLOCK_CYCLES((mod == 3) ? 14 : 17); + return 0; +} +static int opIMUL_w_ib_a32(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + + tempw = geteaw(); if (abrt) return 1; + tempw2 = getbyte(); if (abrt) return 1; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].w = templ & 0xffff; + + CLOCK_CYCLES((mod == 3) ? 14 : 17); + return 0; +} + +static int opIMUL_l_ib_a16(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + templ = geteal(); if (abrt) return 1; + templ2 = getbyte(); if (abrt) return 1; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(20); + return 0; +} +static int opIMUL_l_ib_a32(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + templ = geteal(); if (abrt) return 1; + templ2 = getbyte(); if (abrt) return 1; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(20); + return 0; +} + + + +static int opIMUL_w_w_a16(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_16(fetchdat); + templ = (int32_t)(int16_t)cpu_state.regs[reg].w * (int32_t)(int16_t)geteaw(); + if (abrt) return 1; + cpu_state.regs[reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(18); + return 0; +} +static int opIMUL_w_w_a32(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_32(fetchdat); + templ = (int32_t)(int16_t)cpu_state.regs[reg].w * (int32_t)(int16_t)geteaw(); + if (abrt) return 1; + cpu_state.regs[reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(18); + return 0; +} + +static int opIMUL_l_l_a16(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_16(fetchdat); + temp64 = (int64_t)(int32_t)cpu_state.regs[reg].l * (int64_t)(int32_t)geteal(); + if (abrt) return 1; + cpu_state.regs[reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(30); + return 0; +} +static int opIMUL_l_l_a32(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_32(fetchdat); + temp64 = (int64_t)(int32_t)cpu_state.regs[reg].l * (int64_t)(int32_t)geteal(); + if (abrt) return 1; + cpu_state.regs[reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(30); + return 0; +} + diff --git a/src/x86_ops_pmode.h b/src/x86_ops_pmode.h new file mode 100644 index 000000000..bdda2f3f0 --- /dev/null +++ b/src/x86_ops_pmode.h @@ -0,0 +1,408 @@ +static int opARPL_a16(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_16(fetchdat); + pclog("ARPL_a16\n"); + temp_seg = geteaw(); if (abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[reg].w & 3); + seteaw(temp_seg); if (abrt) return 1; + flags |= Z_FLAG; + } + else + flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + return 0; +} +static int opARPL_a32(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_32(fetchdat); + pclog("ARPL_a32\n"); + temp_seg = geteaw(); if (abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[reg].w & 3); + seteaw(temp_seg); if (abrt) return 1; + flags |= Z_FLAG; + } + else + flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + return 0; +} + +#define opLAR(name, fetch_ea, is32) \ + static int opLAR_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + \ + sel = geteaw(); if (abrt) return 1; \ + \ + flags_rebuild(); \ + if (!(sel & 0xfffc)) { flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (abrt) return 1; \ + } \ + flags &= ~Z_FLAG; \ + if ((desc & 0x1f00) == 0x000) valid = 0; \ + if ((desc & 0x1f00) == 0x800) valid = 0; \ + if ((desc & 0x1f00) == 0xa00) valid = 0; \ + if ((desc & 0x1f00) == 0xd00) valid = 0; \ + if ((desc & 0x1c00) < 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int dpl = (desc >> 13) & 3; \ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + cpu_state.regs[reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00; \ + else \ + cpu_state.regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xff00; \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(11); \ + return abrt; \ + } + +opLAR(w_a16, fetch_ea_16, 0) +opLAR(w_a32, fetch_ea_32, 0) +opLAR(l_a16, fetch_ea_16, 1) +opLAR(l_a32, fetch_ea_32, 1) + +#define opLSL(name, fetch_ea, is32) \ + static int opLSL_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + \ + sel = geteaw(); if (abrt) return 1; \ + flags_rebuild(); \ + flags &= ~Z_FLAG; \ + if (!(sel & 0xfffc)) return 0; /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (abrt) return 1; \ + } \ + if ((desc & 0x1400) == 0x400) valid = 0; /*Interrupt or trap or call gate*/ \ + if ((desc & 0x1f00) == 0x000) valid = 0; /*Invalid*/ \ + if ((desc & 0x1f00) == 0xa00) valid = 0; /*Invalid*/ \ + if ((desc & 0x1c00) != 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int rpl = (desc >> 13) & 3; \ + if (rpl < CPL || rpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + { \ + cpu_state.regs[reg].l = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpu_state.regs[reg].l |= (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0xF) << 16; \ + if (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0x80) \ + { \ + cpu_state.regs[reg].l <<= 12; \ + cpu_state.regs[reg].l |= 0xFFF; \ + } \ + } \ + else \ + cpu_state.regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(10); \ + return abrt; \ + } + +opLSL(w_a16, fetch_ea_16, 0) +opLSL(w_a32, fetch_ea_32, 0) +opLSL(l_a16, fetch_ea_16, 1) +opLSL(l_a32, fetch_ea_32, 1) + + +static int op0F00_common(uint32_t fetchdat) +{ + int dpl, valid, granularity; + uint32_t addr, base, limit; + uint16_t desc, sel; + uint8_t access; + +// pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); + switch (rmdat & 0x38) + { + case 0x00: /*SLDT*/ + seteaw(ldt.seg); + CLOCK_CYCLES(4); + break; + case 0x08: /*STR*/ + seteaw(tr.seg); + CLOCK_CYCLES(4); + break; + case 0x10: /*LLDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LLDT!\n"); + x86gpf(NULL,0); + return 1; + } + sel = geteaw(); if (abrt) return 1; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (abrt) return 1; + ldt.limit = limit; + ldt.access = access; + if (granularity) + { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base = base; + ldt.seg = sel; + CLOCK_CYCLES(20); + break; + case 0x18: /*LTR*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LTR!\n"); + x86gpf(NULL,0); + break; + } + sel = geteaw(); if (abrt) return 1; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (abrt) return 1; + tr.seg = sel; + tr.limit = limit; + tr.access = access; + if (granularity) + { + tr.limit <<= 12; + tr.limit |= 0xFFF; + } + tr.base = base; + CLOCK_CYCLES(20); + break; + case 0x20: /*VERR*/ + sel = geteaw(); if (abrt) return 1; + flags_rebuild(); + flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + if ((desc & 0xC00) != 0xC00) /*Exclude conforming code segments*/ + { + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + } + if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/ + if (valid) flags |= Z_FLAG; + CLOCK_CYCLES(20); + break; + case 0x28: /*VERW*/ + sel = geteaw(); if (abrt) return 1; + flags_rebuild(); + flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + if (desc & 0x0800) valid = 0; /*Code*/ + if (!(desc & 0x0200)) valid = 0; /*Read-only data*/ + if (valid) flags |= Z_FLAG; + CLOCK_CYCLES(20); + break; + + default: + pclog("Bad 0F 00 opcode %02X\n", rmdat & 0x38); + cpu_state.pc -= 3; + x86illegal(); + break; + } + return abrt; +} + +static int op0F00_a16(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_16(fetchdat); + + return op0F00_common(fetchdat); +} +static int op0F00_a32(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_32(fetchdat); + + return op0F00_common(fetchdat); +} + +static int op0F01_common(uint32_t fetchdat, int is32, int is286) +{ + uint32_t base; + uint16_t limit, tempw; +// pclog("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); + switch (rmdat & 0x38) + { + case 0x00: /*SGDT*/ + seteaw(gdt.limit); + base = gdt.base; //is32 ? gdt.base : (gdt.base & 0xffffff); + if (is286) + base |= 0xff000000; + writememl(easeg, eaaddr + 2, base); + CLOCK_CYCLES(7); + break; + case 0x08: /*SIDT*/ + seteaw(idt.limit); + base = idt.base; + if (is286) + base |= 0xff000000; + writememl(easeg, eaaddr + 2, base); + CLOCK_CYCLES(7); + break; + case 0x10: /*LGDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LGDT!\n"); + x86gpf(NULL,0); + break; + } +// pclog("LGDT %08X:%08X\n", easeg, eaaddr); + limit = geteaw(); + base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 1; +// pclog(" %08X %04X\n", base, limit); + gdt.limit = limit; + gdt.base = base; + if (!is32) gdt.base &= 0xffffff; + CLOCK_CYCLES(11); + break; + case 0x18: /*LIDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LIDT!\n"); + x86gpf(NULL,0); + break; + } +// pclog("LIDT %08X:%08X\n", easeg, eaaddr); + limit = geteaw(); + base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 1; +// pclog(" %08X %04X\n", base, limit); + idt.limit = limit; + idt.base = base; + if (!is32) idt.base &= 0xffffff; + CLOCK_CYCLES(11); + break; + + case 0x20: /*SMSW*/ + if (is486) seteaw(msw); + else seteaw(msw | 0xFF00); + CLOCK_CYCLES(2); + break; + case 0x30: /*LMSW*/ + if ((CPL || eflags&VM_FLAG) && (msw&1)) + { + pclog("LMSW - ring not zero!\n"); + x86gpf(NULL, 0); + break; + } + tempw = geteaw(); if (abrt) return 1; + if (msw & 1) tempw |= 1; + msw = tempw; + break; + + case 0x38: /*INVLPG*/ + if (is486) + { + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid INVLPG!\n"); + x86gpf(NULL, 0); + break; + } + mmu_invalidate(ds + eaaddr); + CLOCK_CYCLES(12); + break; + } + + default: + pclog("Bad 0F 01 opcode %02X\n", rmdat & 0x38); + cpu_state.pc -= 3; + x86illegal(); + break; + } + return abrt; +} + +static int op0F01_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 0); +} +static int op0F01_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 0, 0); +} +static int op0F01_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 1, 0); +} +static int op0F01_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 1, 0); +} + +static int op0F01_286(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 1); +} diff --git a/src/x86_ops_prefix.h b/src/x86_ops_prefix.h new file mode 100644 index 000000000..e9eb74caa --- /dev/null +++ b/src/x86_ops_prefix.h @@ -0,0 +1,80 @@ +#define op_seg(name, seg) \ +static int op ## name ## _w_a16(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (abrt) return 1; \ + cpu_state.pc++; \ + \ + ea_seg = &seg; \ + ssegs = 1; \ + CLOCK_CYCLES(4); \ + \ + return x86_opcodes[fetchdat & 0xff](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _l_a16(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (abrt) return 1; \ + cpu_state.pc++; \ + \ + ea_seg = &seg; \ + ssegs = 1; \ + CLOCK_CYCLES(4); \ + \ + return x86_opcodes[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _w_a32(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (abrt) return 1; \ + cpu_state.pc++; \ + \ + ea_seg = &seg; \ + ssegs = 1; \ + CLOCK_CYCLES(4); \ + \ + return x86_opcodes[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _l_a32(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (abrt) return 1; \ + cpu_state.pc++; \ + \ + ea_seg = &seg; \ + ssegs = 1; \ + CLOCK_CYCLES(4); \ + \ + return x86_opcodes[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ +} + +op_seg(CS, _cs) +op_seg(DS, _ds) +op_seg(ES, _es) +op_seg(FS, _fs) +op_seg(GS, _gs) +op_seg(SS, _ss) + +static int op_66(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (abrt) return 1; + cpu_state.pc++; + + op32 = ((use32 & 0x100) ^ 0x100) | (op32 & 0x200); + CLOCK_CYCLES(2); + return x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); +} +static int op_67(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (abrt) return 1; + cpu_state.pc++; + + op32 = ((use32 & 0x200) ^ 0x200) | (op32 & 0x100); + CLOCK_CYCLES(2); + return x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); +} diff --git a/src/x86_ops_rep.h b/src/x86_ops_rep.h new file mode 100644 index 000000000..4c94cd428 --- /dev/null +++ b/src/x86_ops_rep.h @@ -0,0 +1,9 @@ +static int opREPNE(uint32_t fetchdat) +{ + return rep386(0); +} +static int opREPE(uint32_t fetchdat) +{ + return rep386(1); +} + diff --git a/src/x86_ops_ret.h b/src/x86_ops_ret.h new file mode 100644 index 000000000..384491fe2 --- /dev/null +++ b/src/x86_ops_ret.h @@ -0,0 +1,194 @@ +#define RETF_a16(stack_offset) \ + if ((msw&1) && !(eflags&VM_FLAG)) \ + { \ + pmoderetf(0, stack_offset); \ + return 1; \ + } \ + oxpc = cpu_state.pc; \ + if (stack32) \ + { \ + cpu_state.pc = readmemw(ss, ESP); \ + loadcs(readmemw(ss, ESP + 2)); \ + } \ + else \ + { \ + cpu_state.pc = readmemw(ss, SP); \ + loadcs(readmemw(ss, SP + 2)); \ + } \ + if (abrt) return 1; \ + if (stack32) ESP += 4 + stack_offset; \ + else SP += 4 + stack_offset; \ + cycles -= timing_retf_rm; + +#define RETF_a32(stack_offset) \ + if ((msw&1) && !(eflags&VM_FLAG)) \ + { \ + pmoderetf(1, stack_offset); \ + return 1; \ + } \ + oxpc = cpu_state.pc; \ + if (stack32) \ + { \ + cpu_state.pc = readmeml(ss, ESP); \ + loadcs(readmeml(ss, ESP + 4) & 0xffff); \ + } \ + else \ + { \ + cpu_state.pc = readmeml(ss, SP); \ + loadcs(readmeml(ss, SP + 4) & 0xffff); \ + } \ + if (abrt) return 1; \ + if (stack32) ESP += 8 + stack_offset; \ + else SP += 8 + stack_offset; \ + cycles -= timing_retf_rm; + +static int opRETF_a16(uint32_t fetchdat) +{ + CPU_BLOCK_END(); + RETF_a16(0); + return 0; +} +static int opRETF_a32(uint32_t fetchdat) +{ + CPU_BLOCK_END(); + RETF_a32(0); + return 0; +} + +static int opRETF_a16_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + CPU_BLOCK_END(); + RETF_a16(offset); + return 0; +} +static int opRETF_a32_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + CPU_BLOCK_END(); + RETF_a32(offset); + return 0; +} + +static int opIRET_286(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + flags = (flags & 0x7000) | (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + flags = (flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + return abrt; +} + +static int opIRET(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + return abrt; +} + +static int opIRETD(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw & 1) + { + optype = IRET; + pmodeiret(1); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmeml(ss, ESP); + new_cs = readmemw(ss, ESP + 4); + flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2; + eflags = readmemw(ss, ESP + 10); + ESP += 12; + } + else + { + cpu_state.pc = readmeml(ss, SP); + new_cs = readmemw(ss, ((SP + 4) & 0xffff)); + flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2; + eflags = readmemw(ss, (SP + 10) & 0xffff); + SP += 12; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + return abrt; +} + diff --git a/src/x86_ops_set.h b/src/x86_ops_set.h new file mode 100644 index 000000000..de39bdefc --- /dev/null +++ b/src/x86_ops_set.h @@ -0,0 +1,33 @@ +#define opSET(condition) \ + static int opSET ## condition ## _a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + seteab((cond_ ## condition) ? 1 : 0); \ + CLOCK_CYCLES(4); \ + return abrt; \ + } \ + \ + static int opSET ## condition ## _a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + seteab((cond_ ## condition) ? 1 : 0); \ + CLOCK_CYCLES(4); \ + return abrt; \ + } + +opSET(O) +opSET(NO) +opSET(B) +opSET(NB) +opSET(E) +opSET(NE) +opSET(BE) +opSET(NBE) +opSET(S) +opSET(NS) +opSET(P) +opSET(NP) +opSET(L) +opSET(NL) +opSET(LE) +opSET(NLE) diff --git a/src/x86_ops_shift.h b/src/x86_ops_shift.h new file mode 100644 index 000000000..955c0aa8b --- /dev/null +++ b/src/x86_ops_shift.h @@ -0,0 +1,571 @@ +#define OP_SHIFT_b(c) \ + { \ + uint8_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL b, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x80) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteab(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x08: /*ROR b,CL*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x80; \ + c--; \ + } \ + seteab(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x10: /*RCL b,CL*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x18: /*RCR b,CL*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x20: case 0x30: /*SHL b,CL*/ \ + seteab(temp << c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHL8, temp_orig, c, (temp << c) & 0xff); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x28: /*SHR b,CL*/ \ + seteab(temp >> c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHR8, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x38: /*SAR b,CL*/ \ + temp = (int8_t)temp >> c; \ + seteab(temp); if (abrt) return 1; \ + set_flags_shift(FLAGS_SAR8, temp_orig, c, temp); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + } \ + } + +#define OP_SHIFT_w(c) \ + { \ + uint16_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL w, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x8000) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x08: /*ROR w, c*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x8000; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x10: /*RCL w, c*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x8000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x18: /*RCR w, c*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x8000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x20: case 0x30: /*SHL w, c*/ \ + seteaw(temp << c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHL16, temp_orig, c, (temp << c) & 0xffff); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x28: /*SHR w, c*/ \ + seteaw(temp >> c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHR16, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x38: /*SAR w, c*/ \ + temp = (int16_t)temp >> c; \ + seteaw(temp); if (abrt) return 1; \ + set_flags_shift(FLAGS_SAR16, temp_orig, c, temp); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + } \ + } + +#define OP_SHIFT_l(c) \ + { \ + uint32_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL l, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x80000000) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteal(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x08: /*ROR l, c*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x80000000; \ + c--; \ + } \ + seteal(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x10: /*RCL l, c*/ \ + temp2 = CF_SET(); \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80000000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x18: /*RCR l, c*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80000000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x20: case 0x30: /*SHL l, c*/ \ + seteal(temp << c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHL32, temp_orig, c, temp << c); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x28: /*SHR l, c*/ \ + seteal(temp >> c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHR32, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x38: /*SAR l, c*/ \ + temp = (int32_t)temp >> c; \ + seteal(temp); if (abrt) return 1; \ + set_flags_shift(FLAGS_SAR32, temp_orig, c, temp); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + } \ + } + +static int opC0_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_16(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opC0_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_32(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opC1_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_16(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opC1_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_32(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opC1_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_16(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} +static int opC1_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_32(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} + +static int opD0_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opD0_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opD1_w_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opD1_w_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opD1_l_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2; + + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} +static int opD1_l_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2; + + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} + +static int opD2_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opD2_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opD3_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opD3_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opD3_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} +static int opD3_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} + + +#define SHLD_w() \ + if (count) \ + { \ + uint16_t tempw = geteaw(); if (abrt) return 1; \ + int tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \ + uint32_t templ = (tempw << 16) | cpu_state.regs[reg].w; \ + if (count <= 16) tempw = templ >> (16 - count); \ + else tempw = (templ << count) >> 16; \ + seteaw(tempw); if (abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define SHLD_l() \ + if (count) \ + { \ + uint32_t templ = geteal(); if (abrt) return 1; \ + int tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \ + templ = (templ << count) | (cpu_state.regs[reg].l >> (32 - count)); \ + seteal(templ); if (abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + + +#define SHRD_w() \ + if (count) \ + { \ + uint16_t tempw = geteaw(); if (abrt) return 1; \ + int tempc = (tempw >> (count - 1)) & 1; \ + uint32_t templ = tempw | (cpu_state.regs[reg].w << 16); \ + tempw = templ >> count; \ + seteaw(tempw); if (abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define SHRD_l() \ + if (count) \ + { \ + uint32_t templ = geteal(); if (abrt) return 1; \ + int tempc = (templ >> (count - 1)) & 1; \ + templ = (templ >> count) | (cpu_state.regs[reg].l << (32 - count)); \ + seteal(templ); if (abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define opSHxD(operation) \ + static int op ## operation ## _i_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + count = getbyte() & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + return 0; \ + } \ + static int op ## operation ## _CL_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + count = CL & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + return 0; \ + } \ + static int op ## operation ## _i_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + count = getbyte() & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + return 0; \ + } \ + static int op ## operation ## _CL_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + count = CL & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + return 0; \ + } + +opSHxD(SHLD_w) +opSHxD(SHLD_l) +opSHxD(SHRD_w) +opSHxD(SHRD_l) diff --git a/src/x86_ops_stack.h b/src/x86_ops_stack.h new file mode 100644 index 000000000..5b6565f47 --- /dev/null +++ b/src/x86_ops_stack.h @@ -0,0 +1,476 @@ +#define PUSH_W_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_W(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + return abrt; \ + } + +#define PUSH_L_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_L(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + return abrt; \ + } + +#define POP_W_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_W(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + return abrt; \ + } + +#define POP_L_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_L(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + return abrt; \ + } + +PUSH_W_OP(AX) +PUSH_W_OP(BX) +PUSH_W_OP(CX) +PUSH_W_OP(DX) +PUSH_W_OP(SI) +PUSH_W_OP(DI) +PUSH_W_OP(BP) +PUSH_W_OP(SP) + +PUSH_L_OP(EAX) +PUSH_L_OP(EBX) +PUSH_L_OP(ECX) +PUSH_L_OP(EDX) +PUSH_L_OP(ESI) +PUSH_L_OP(EDI) +PUSH_L_OP(EBP) +PUSH_L_OP(ESP) + +POP_W_OP(AX) +POP_W_OP(BX) +POP_W_OP(CX) +POP_W_OP(DX) +POP_W_OP(SI) +POP_W_OP(DI) +POP_W_OP(BP) +POP_W_OP(SP) + +POP_L_OP(EAX) +POP_L_OP(EBX) +POP_L_OP(ECX) +POP_L_OP(EDX) +POP_L_OP(ESI) +POP_L_OP(EDI) +POP_L_OP(EBP) +POP_L_OP(ESP) + + +static int opPUSHA_w(uint32_t fetchdat) +{ + if (stack32) + { + writememw(ss, ESP - 2, AX); + writememw(ss, ESP - 4, CX); + writememw(ss, ESP - 6, DX); + writememw(ss, ESP - 8, BX); + writememw(ss, ESP - 10, SP); + writememw(ss, ESP - 12, BP); + writememw(ss, ESP - 14, SI); + writememw(ss, ESP - 16, DI); + if (!abrt) ESP -= 16; + } + else + { + writememw(ss, ((SP - 2) & 0xFFFF), AX); + writememw(ss, ((SP - 4) & 0xFFFF), CX); + writememw(ss, ((SP - 6) & 0xFFFF), DX); + writememw(ss, ((SP - 8) & 0xFFFF), BX); + writememw(ss, ((SP - 10) & 0xFFFF), SP); + writememw(ss, ((SP - 12) & 0xFFFF), BP); + writememw(ss, ((SP - 14) & 0xFFFF), SI); + writememw(ss, ((SP - 16) & 0xFFFF), DI); + if (!abrt) SP -= 16; + } + CLOCK_CYCLES((is486) ? 11 : 18); + return abrt; +} +static int opPUSHA_l(uint32_t fetchdat) +{ + if (stack32) + { + writememl(ss, ESP - 4, EAX); + writememl(ss, ESP - 8, ECX); + writememl(ss, ESP - 12, EDX); + writememl(ss, ESP - 16, EBX); + writememl(ss, ESP - 20, ESP); + writememl(ss, ESP - 24, EBP); + writememl(ss, ESP - 28, ESI); + writememl(ss, ESP - 32, EDI); + if (!abrt) ESP -= 32; + } + else + { + writememl(ss, ((SP - 4) & 0xFFFF), EAX); + writememl(ss, ((SP - 8) & 0xFFFF), ECX); + writememl(ss, ((SP - 12) & 0xFFFF), EDX); + writememl(ss, ((SP - 16) & 0xFFFF), EBX); + writememl(ss, ((SP - 20) & 0xFFFF), ESP); + writememl(ss, ((SP - 24) & 0xFFFF), EBP); + writememl(ss, ((SP - 28) & 0xFFFF), ESI); + writememl(ss, ((SP - 32) & 0xFFFF), EDI); + if (!abrt) SP -= 32; + } + CLOCK_CYCLES((is486) ? 11 : 18); + return abrt; +} + +static int opPOPA_w(uint32_t fetchdat) +{ + if (stack32) + { + DI = readmemw(ss, ESP); if (abrt) return 1; + SI = readmemw(ss, ESP + 2); if (abrt) return 1; + BP = readmemw(ss, ESP + 4); if (abrt) return 1; + BX = readmemw(ss, ESP + 8); if (abrt) return 1; + DX = readmemw(ss, ESP + 10); if (abrt) return 1; + CX = readmemw(ss, ESP + 12); if (abrt) return 1; + AX = readmemw(ss, ESP + 14); if (abrt) return 1; + ESP += 16; + } + else + { + DI = readmemw(ss, ((SP) & 0xFFFF)); if (abrt) return 1; + SI = readmemw(ss, ((SP + 2) & 0xFFFF)); if (abrt) return 1; + BP = readmemw(ss, ((SP + 4) & 0xFFFF)); if (abrt) return 1; + BX = readmemw(ss, ((SP + 8) & 0xFFFF)); if (abrt) return 1; + DX = readmemw(ss, ((SP + 10) & 0xFFFF)); if (abrt) return 1; + CX = readmemw(ss, ((SP + 12) & 0xFFFF)); if (abrt) return 1; + AX = readmemw(ss, ((SP + 14) & 0xFFFF)); if (abrt) return 1; + SP += 16; + } + CLOCK_CYCLES((is486) ? 9 : 24); + return 0; +} +static int opPOPA_l(uint32_t fetchdat) +{ + if (stack32) + { + EDI = readmeml(ss, ESP); if (abrt) return 1; + ESI = readmeml(ss, ESP + 4); if (abrt) return 1; + EBP = readmeml(ss, ESP + 8); if (abrt) return 1; + EBX = readmeml(ss, ESP + 16); if (abrt) return 1; + EDX = readmeml(ss, ESP + 20); if (abrt) return 1; + ECX = readmeml(ss, ESP + 24); if (abrt) return 1; + EAX = readmeml(ss, ESP + 28); if (abrt) return 1; + ESP += 32; + } + else + { + EDI = readmeml(ss, ((SP) & 0xFFFF)); if (abrt) return 1; + ESI = readmeml(ss, ((SP + 4) & 0xFFFF)); if (abrt) return 1; + EBP = readmeml(ss, ((SP + 8) & 0xFFFF)); if (abrt) return 1; + EBX = readmeml(ss, ((SP + 16) & 0xFFFF)); if (abrt) return 1; + EDX = readmeml(ss, ((SP + 20) & 0xFFFF)); if (abrt) return 1; + ECX = readmeml(ss, ((SP + 24) & 0xFFFF)); if (abrt) return 1; + EAX = readmeml(ss, ((SP + 28) & 0xFFFF)); if (abrt) return 1; + SP += 32; + } + CLOCK_CYCLES((is486) ? 9 : 24); + return 0; +} + +static int opPUSH_imm_w(uint32_t fetchdat) +{ + uint16_t val = getwordf(); + PUSH_W(val); + CLOCK_CYCLES(2); + return abrt; +} +static int opPUSH_imm_l(uint32_t fetchdat) +{ + uint32_t val = getlong(); if (abrt) return 1; + PUSH_L(val); + CLOCK_CYCLES(2); + return abrt; +} + +static int opPUSH_imm_bw(uint32_t fetchdat) +{ + uint16_t tempw = getbytef(); + + if (tempw & 0x80) tempw |= 0xFF00; + PUSH_W(tempw); + + CLOCK_CYCLES(2); + return abrt; +} +static int opPUSH_imm_bl(uint32_t fetchdat) +{ + uint32_t templ = getbytef(); + + if (templ & 0x80) templ |= 0xFFFFFF00; + PUSH_L(templ); + + CLOCK_CYCLES(2); + return abrt; +} + +static int opPOPW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + temp = POP_W(); if (abrt) return 1; + + fetch_ea_16(fetchdat); + seteaw(temp); + if (abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 6); + else CLOCK_CYCLES((mod == 3) ? 4 : 5); + return abrt; +} +static int opPOPW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + temp = POP_W(); if (abrt) return 1; + + fetch_ea_32(fetchdat); + seteaw(temp); + if (abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 6); + else CLOCK_CYCLES((mod == 3) ? 4 : 5); + return abrt; +} + +static int opPOPL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + temp = POP_L(); if (abrt) return 1; + + fetch_ea_16(fetchdat); + seteal(temp); + if (abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 6); + else CLOCK_CYCLES((mod == 3) ? 4 : 5); + return abrt; +} +static int opPOPL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + temp = POP_L(); if (abrt) return 1; + + fetch_ea_32(fetchdat); + seteal(temp); + if (abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 6); + else CLOCK_CYCLES((mod == 3) ? 4 : 5); + return abrt; +} + + +static int opENTER_w(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr; + + PUSH_W(BP); if (abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + uint16_t tempw; + + BP -= 2; + tempw = readmemw(ss, BP); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_W(tempw); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + } + PUSH_W(frame_ptr); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + } + BP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + return 0; +} +static int opENTER_l(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr; + + PUSH_L(EBP); if (abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + uint32_t templ; + + EBP -= 4; + templ = readmeml(ss, EBP); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_L(templ); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + } + PUSH_L(frame_ptr); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + } + EBP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + return 0; +} + + +static int opLEAVE_w(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint16_t temp; + + SP = BP; + temp = POP_W(); + if (abrt) { ESP = tempESP; return 1; } + BP = temp; + + CLOCK_CYCLES(4); + return 0; +} +static int opLEAVE_l(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint32_t temp; + + ESP = EBP; + temp = POP_L(); + if (abrt) { ESP = tempESP; return 1; } + EBP = temp; + + CLOCK_CYCLES(4); + return 0; +} + + +#define PUSH_SEG_OPS(seg) \ + static int opPUSH_ ## seg ## _w(uint32_t fetchdat) \ + { \ + PUSH_W(seg); \ + CLOCK_CYCLES(2); \ + return abrt; \ + } \ + static int opPUSH_ ## seg ## _l(uint32_t fetchdat) \ + { \ + PUSH_L(seg); \ + CLOCK_CYCLES(2); \ + return abrt; \ + } + +#define POP_SEG_OPS(seg, realseg) \ + static int opPOP_ ## seg ## _w(uint32_t fetchdat) \ + { \ + uint16_t temp_seg; \ + uint32_t temp_esp = ESP; \ + temp_seg = POP_W(); if (abrt) return 1; \ + loadseg(temp_seg, realseg); if (abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + return abrt; \ + } \ + static int opPOP_ ## seg ## _l(uint32_t fetchdat) \ + { \ + uint32_t temp_seg; \ + uint32_t temp_esp = ESP; \ + temp_seg = POP_L(); if (abrt) return 1; \ + loadseg(temp_seg & 0xffff, realseg); if (abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + return abrt; \ + } + + +PUSH_SEG_OPS(CS); +PUSH_SEG_OPS(DS); +PUSH_SEG_OPS(ES); +PUSH_SEG_OPS(FS); +PUSH_SEG_OPS(GS); +PUSH_SEG_OPS(SS); + +POP_SEG_OPS(DS, &_ds); +POP_SEG_OPS(ES, &_es); +POP_SEG_OPS(FS, &_fs); +POP_SEG_OPS(GS, &_gs); + + +static int opPOP_SS_w(uint32_t fetchdat) +{ + uint16_t temp_seg; + uint32_t temp_esp = ESP; + temp_seg = POP_W(); if (abrt) return 1; + loadseg(temp_seg, &_ss); if (abrt) { ESP = temp_esp; return 1; } + CLOCK_CYCLES(is486 ? 3 : 7); + + oldpc = cpu_state.pc; + op32 = use32; + ssegs = 0; + ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); + + return 1; +} +static int opPOP_SS_l(uint32_t fetchdat) +{ + uint32_t temp_seg; + uint32_t temp_esp = ESP; + temp_seg = POP_L(); if (abrt) return 1; + loadseg(temp_seg & 0xffff, &_ss); if (abrt) { ESP = temp_esp; return 1; } + CLOCK_CYCLES(is486 ? 3 : 7); + + oldpc = cpu_state.pc; + op32 = use32; + ssegs = 0; + ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); + + return 1; +} diff --git a/src/x86_ops_string.h b/src/x86_ops_string.h new file mode 100644 index 000000000..010fd37b9 --- /dev/null +++ b/src/x86_ops_string.h @@ -0,0 +1,435 @@ +static int opMOVSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, SI); if (abrt) return 1; + writememb(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + CLOCK_CYCLES(7); + return 0; +} +static int opMOVSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, ESI); if (abrt) return 1; + writememb(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + CLOCK_CYCLES(7); + return 0; +} + +static int opMOVSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, SI); if (abrt) return 1; + writememw(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + CLOCK_CYCLES(7); + return 0; +} +static int opMOVSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, ESI); if (abrt) return 1; + writememw(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + CLOCK_CYCLES(7); + return 0; +} + +static int opMOVSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, SI); if (abrt) return 1; + writememl(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + CLOCK_CYCLES(7); + return 0; +} +static int opMOVSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, ESI); if (abrt) return 1; + writememl(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + CLOCK_CYCLES(7); + return 0; +} + + +static int opCMPSB_a16(uint32_t fetchdat) +{ + uint8_t src = readmemb(ea_seg->base, SI); + uint8_t dst = readmemb(es, DI); if (abrt) return 1; + setsub8(src, dst); + if (flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} +static int opCMPSB_a32(uint32_t fetchdat) +{ + uint8_t src = readmemb(ea_seg->base, ESI); + uint8_t dst = readmemb(es, EDI); if (abrt) return 1; + setsub8(src, dst); + if (flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} + +static int opCMPSW_a16(uint32_t fetchdat) +{ + uint16_t src = readmemw(ea_seg->base, SI); + uint16_t dst = readmemw(es, DI); if (abrt) return 1; + setsub16(src, dst); + if (flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} +static int opCMPSW_a32(uint32_t fetchdat) +{ + uint16_t src = readmemw(ea_seg->base, ESI); + uint16_t dst = readmemw(es, EDI); if (abrt) return 1; + setsub16(src, dst); + if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} + +static int opCMPSL_a16(uint32_t fetchdat) +{ + uint32_t src = readmeml(ea_seg->base, SI); + uint32_t dst = readmeml(es, DI); if (abrt) return 1; + setsub32(src, dst); + if (flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} +static int opCMPSL_a32(uint32_t fetchdat) +{ + uint32_t src = readmeml(ea_seg->base, ESI); + uint32_t dst = readmeml(es, EDI); if (abrt) return 1; + setsub32(src, dst); + if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} + +static int opSTOSB_a16(uint32_t fetchdat) +{ + writememb(es, DI, AL); if (abrt) return 1; + if (flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(4); + return 0; +} +static int opSTOSB_a32(uint32_t fetchdat) +{ + writememb(es, EDI, AL); if (abrt) return 1; + if (flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(4); + return 0; +} + +static int opSTOSW_a16(uint32_t fetchdat) +{ + writememw(es, DI, AX); if (abrt) return 1; + if (flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(4); + return 0; +} +static int opSTOSW_a32(uint32_t fetchdat) +{ + writememw(es, EDI, AX); if (abrt) return 1; + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(4); + return 0; +} + +static int opSTOSL_a16(uint32_t fetchdat) +{ + writememl(es, DI, EAX); if (abrt) return 1; + if (flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(4); + return 0; +} +static int opSTOSL_a32(uint32_t fetchdat) +{ + writememl(es, EDI, EAX); if (abrt) return 1; + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(4); + return 0; +} + + +static int opLODSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, SI); if (abrt) return 1; + AL = temp; + if (flags & D_FLAG) SI--; + else SI++; + CLOCK_CYCLES(5); + return 0; +} +static int opLODSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, ESI); if (abrt) return 1; + AL = temp; + if (flags & D_FLAG) ESI--; + else ESI++; + CLOCK_CYCLES(5); + return 0; +} + +static int opLODSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, SI); if (abrt) return 1; + AX = temp; + if (flags & D_FLAG) SI -= 2; + else SI += 2; + CLOCK_CYCLES(5); + return 0; +} +static int opLODSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, ESI); if (abrt) return 1; + AX = temp; + if (flags & D_FLAG) ESI -= 2; + else ESI += 2; + CLOCK_CYCLES(5); + return 0; +} + +static int opLODSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, SI); if (abrt) return 1; + EAX = temp; + if (flags & D_FLAG) SI -= 4; + else SI += 4; + CLOCK_CYCLES(5); + return 0; +} +static int opLODSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, ESI); if (abrt) return 1; + EAX = temp; + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + CLOCK_CYCLES(5); + return 0; +} + + +static int opSCASB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(es, DI); if (abrt) return 1; + setsub8(AL, temp); + if (flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(7); + return 0; +} +static int opSCASB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(es, EDI); if (abrt) return 1; + setsub8(AL, temp); + if (flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(7); + return 0; +} + +static int opSCASW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(es, DI); if (abrt) return 1; + setsub16(AX, temp); + if (flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(7); + return 0; +} +static int opSCASW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(es, EDI); if (abrt) return 1; + setsub16(AX, temp); + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(7); + return 0; +} + +static int opSCASL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(es, DI); if (abrt) return 1; + setsub32(EAX, temp); + if (flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(7); + return 0; +} +static int opSCASL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(es, EDI); if (abrt) return 1; + setsub32(EAX, temp); + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(7); + return 0; +} + +static int opINSB_a16(uint32_t fetchdat) +{ + uint8_t temp; + check_io_perm(DX); + temp = inb(DX); + writememb(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(15); + return 0; +} +static int opINSB_a32(uint32_t fetchdat) +{ + uint8_t temp; + check_io_perm(DX); + temp = inb(DX); + writememb(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(15); + return 0; +} + +static int opINSW_a16(uint32_t fetchdat) +{ + uint16_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(15); + return 0; +} +static int opINSW_a32(uint32_t fetchdat) +{ + uint16_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(15); + return 0; +} + +static int opINSL_a16(uint32_t fetchdat) +{ + uint32_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(15); + return 0; +} +static int opINSL_a32(uint32_t fetchdat) +{ + uint32_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(15); + return 0; +} + +static int opOUTSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, SI); if (abrt) return 1; + check_io_perm(DX); + if (flags & D_FLAG) SI--; + else SI++; + outb(DX, temp); + CLOCK_CYCLES(14); + return 0; +} +static int opOUTSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, ESI); if (abrt) return 1; + check_io_perm(DX); + if (flags & D_FLAG) ESI--; + else ESI++; + outb(DX, temp); + CLOCK_CYCLES(14); + return 0; +} + +static int opOUTSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, SI); if (abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + if (flags & D_FLAG) SI -= 2; + else SI += 2; + outw(DX, temp); + CLOCK_CYCLES(14); + return 0; +} +static int opOUTSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, ESI); if (abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + if (flags & D_FLAG) ESI -= 2; + else ESI += 2; + outw(DX, temp); + CLOCK_CYCLES(14); + return 0; +} + +static int opOUTSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, SI); if (abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (flags & D_FLAG) SI -= 4; + else SI += 4; + outl(EDX, temp); + CLOCK_CYCLES(14); + return 0; +} +static int opOUTSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, ESI); if (abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + outl(EDX, temp); + CLOCK_CYCLES(14); + return 0; +} diff --git a/src/x86_ops_xchg.h b/src/x86_ops_xchg.h new file mode 100644 index 000000000..55a3d4a58 --- /dev/null +++ b/src/x86_ops_xchg.h @@ -0,0 +1,195 @@ +static int opXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + seteab(getr8(reg)); if (abrt) return 1; + setr8(reg, temp); + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} +static int opXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + seteab(getr8(reg)); if (abrt) return 1; + setr8(reg, temp); + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} + +static int opXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + seteaw(cpu_state.regs[reg].w); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} +static int opXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + seteaw(cpu_state.regs[reg].w); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} + +static int opXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + seteal(cpu_state.regs[reg].l); if (abrt) return 1; + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} +static int opXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + seteal(cpu_state.regs[reg].l); if (abrt) return 1; + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} + + +static int opXCHG_AX_BX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BX; + BX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_CX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = CX; + CX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_DX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DX; + DX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_SI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SI; + SI = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_DI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DI; + DI = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_BP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BP; + BP = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_SP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SP; + SP = temp; + CLOCK_CYCLES(3); + return 0; +} + +static int opXCHG_EAX_EBX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBX; + EBX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_ECX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ECX; + ECX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_EDX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDX; + EDX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_ESI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESI; + ESI = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_EDI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDI; + EDI = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_EBP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBP; + EBP = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_ESP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESP; + ESP = temp; + CLOCK_CYCLES(3); + return 0; +} + + +#define opBSWAP(reg) \ + static int opBSWAP_ ## reg(uint32_t fetchdat) \ + { \ + reg = (reg >> 24) | ((reg >> 8) & 0xff00) | ((reg << 8) & 0xff0000) | ((reg << 24) & 0xff000000); \ + CLOCK_CYCLES(1); \ + return 0; \ + } + +opBSWAP(EAX) +opBSWAP(EBX) +opBSWAP(ECX) +opBSWAP(EDX) +opBSWAP(ESI) +opBSWAP(EDI) +opBSWAP(EBP) +opBSWAP(ESP) diff --git a/src/x86seg.c b/src/x86seg.c new file mode 100644 index 000000000..c72d6c80f --- /dev/null +++ b/src/x86seg.c @@ -0,0 +1,2597 @@ +//#if 0 +#include +#include +#include +#include "ibm.h" +#include "mem.h" +#include "x86.h" +#include "386.h" +#include "cpu.h" + +/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ +#define CS_ACCESSED + +/*Controls whether the accessed bit in a descriptor is set when a data or stack + selector is loaded.*/ +#define SEL_ACCESSED +int stimes = 0; +int dtimes = 0; +int btimes = 0; +int is486=1; + +uint32_t abrt_error; +int cgate16,cgate32; + +#define breaknullsegs 0 + +int intgatesize; + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); +void taskswitch386(uint16_t seg, uint16_t *segdat); + +int output; +void pmodeint(int num, int soft); +/*NOT PRESENT is INT 0B + GPF is INT 0D*/ + +FILE *pclogf; +void x86abort(const char *format, ...) +{ + char buf[256]; +// return; + if (!pclogf) + pclogf=fopen("pclog.txt","wt"); +//return; + va_list ap; + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + fputs(buf,pclogf); + fflush(pclogf); + dumpregs(); + exit(-1); +} + +uint8_t opcode2; + +static void seg_reset(x86seg *s) +{ + s->access = (0 << 5) | 2 | 0x80; + s->limit = 0xFFFF; + s->limit_low = 0; + s->limit_high = 0xffff; +} + +void x86seg_reset() +{ + seg_reset(&_cs); + seg_reset(&_ds); + seg_reset(&_es); + seg_reset(&_fs); + seg_reset(&_gs); + seg_reset(&_ss); +} + +void x86_doabrt(int x86_abrt) +{ +// ingpf = 1; + CS = oldcs; + cpu_state.pc = oldpc; + _cs.access = (oldcpl << 5) | 0x80; +// pclog("x86_doabrt - %02X %08X %04X:%08X %i\n", x86_abrt, abrt_error, CS, pc, ins); + +/* if (CS == 0x3433 && cpu_state.pc == 0x000006B0) + { + pclog("Quit it\n"); + dumpregs(); + exit(-1); + }*/ +// pclog("GPF! - error %04X %04X(%08X):%08X %02X %02X %i %04X %i %i\n",error,CS,cs,cpu_state.pc,opcode,opcode2,ins,flags&I_FLAG,IOPL, dtimes); + + if (msw & 1) + pmodeint(x86_abrt, 0); + else + { + uint32_t addr = (x86_abrt << 2) + idt.base; + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + return; + } + + if (abrt) return; + + if (intgatesize == 16) + { + if (stack32) + { + writememw(ss, ESP-2, abrt_error); + ESP-=2; + } + else + { + writememw(ss, ((SP-2)&0xFFFF), abrt_error); + SP-=2; + } + } + else + { + if (stack32) + { + writememl(ss, ESP-4, abrt_error); + ESP-=4; + } + else + { + writememl(ss, ((SP-4)&0xFFFF), abrt_error); + SP-=4; + } + } +// ingpf = 0; +// abrt = gpf = 1; +} +void x86gpf(char *s, uint16_t error) +{ + // pclog("GPF %04X : %s\n", error, s); + abrt = ABRT_GPF; + abrt_error = error; +} +void x86ss(char *s, uint16_t error) +{ + // pclog("SS %04X\n", error); + abrt = ABRT_SS; + abrt_error = error; +} +void x86ts(char *s, uint16_t error) +{ + // pclog("TS %04X\n", error); + abrt = ABRT_TS; + abrt_error = error; +} +void x86np(char *s, uint16_t error) +{ + // pclog("NP %04X : %s\n", error, s); + abrt = ABRT_NP; + abrt_error = error; +} + + +void do_seg_load(x86seg *s, uint16_t *segdat) +{ + s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); + if (segdat[3] & 0x80) + s->limit = (s->limit << 12) | 0xFFF; + s->base = segdat[1] | ((segdat[2] & 0xFF) << 16); + if (is386) + s->base |= ((segdat[3] >> 8) << 24); + s->access = segdat[2] >> 8; + + if ((segdat[2] & 0x1800) != 0x1000 || !(segdat[2] & (1 << 10))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } +// if (output) pclog("SEG : base=%08x limit=%08x low=%08x high=%08x\n", s->base, s->limit, s->limit_low, s->limit_high); +} + +static void do_seg_v86_init(x86seg *s) +{ + s->access = (3 << 5) | 2 | 0x80; + s->limit = 0xffff; + s->limit_low = 0; + s->limit_high = 0xffff; +} + +static void check_seg_valid(x86seg *s) +{ + int dpl = (s->access >> 5) & 3; + int valid = 1; + + if (s->seg & 4) + { + if ((s->seg & ~7) >= ldt.limit) + { +// pclog("Bigger than LDT limit %04X %04X %02X %02X %02X\n", s->seg, ldt.limit, opcode, opcode2, rmdat); + valid = 0; + } + } + else + { + if ((s->seg & ~7) >= gdt.limit) + { +// pclog("Bigger than GDT limit %04X %04X\n", s->seg, gdt.limit); + valid = 0; + } + } + + switch (s->access & 0x1f) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ + if ((s->seg & 3) > dpl || (CPL) > dpl) + { +// pclog("Data seg fail - %04X:%08X %04X %i\n", CS, cpu_state.pc, s->seg, dpl); + valid = 0; + break; + } + break; + + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + + default: + valid = 0; + break; + } + + if (!valid) + loadseg(0, s); +} + +void loadseg(uint16_t seg, x86seg *s) +{ + uint16_t segdat[4]; + uint32_t addr; + int dpl; + + if (msw&1 && !(eflags&VM_FLAG)) + { +// intcount++; + if (!(seg&~3)) + { + if (s==&_ss) + { + pclog("SS selector = NULL!\n"); + x86ss(NULL,0); + return; +// dumpregs(); +// exit(-1); + } +// if (s->base!=-1) pclog("NEW! "); + s->seg=0; + // s->access = 0; + s->access = 0x80; + s->base=-1; +// pclog("NULL selector %s%s%s%s %04X(%06X):%06X\n",(s==&_ds)?"DS":"",(s==&_es)?"ES":"",(s==&_fs)?"FS":"",(s==&_gs)?"GS":"",CS,cs,cpu_state.pc); + return; + } +// if (s==&_ss) pclog("Load SS %04X\n",seg); +// pclog("Protected mode seg load!\n"); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X %02X %02X %02X\n",seg,ldt.limit, opcode, opcode2, rmdat); +// dumppic(); +// dumpregs(); +// exit(-1); + x86gpf("loadseg(): Bigger than LDT limit",seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X 1\n",seg,gdt.limit); +// dumpregs(); +// exit(-1); + x86gpf("loadseg(): Bigger than GDT limit",seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + dpl=(segdat[2]>>13)&3; + if (s==&_ss) + { + if (!(seg&~3)) + { + pclog("Load SS null selector\n"); + x86gpf(NULL,seg&~3); + return; + } + if ((seg&3)!=CPL || dpl!=CPL) + { + pclog("Invalid SS permiss\n"); + x86gpf(NULL,seg&~3); +// x86abort("Invalid SS permiss for %04X!\n",seg&0xFFFC); + return; + } + switch ((segdat[2]>>8)&0x1F) + { + case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ + break; + default: + pclog("Invalid SS type\n"); + x86gpf(NULL,seg&~3); +// x86abort("Invalid SS segment type for %04X!\n",seg&0xFFFC); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("Load SS not present!\n"); + x86ss(NULL,seg&~3); + return; + } + stack32 = (segdat[3] & 0x40) ? 1 : 0; +// pclog("Load SS %04x %04x %04x %04x\n", segdat[0], segdat[1], segdat[2], segdat[3]); + } + else if (s!=&_cs) + { + if (output) pclog("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + if (output) pclog("Seg type %03X\n",segdat[2]&0x1F00); + switch ((segdat[2]>>8)&0x1F) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ +// pclog("Load seg %04X %i %i %04X:%08X\n",seg,dpl,CS&3,CS,cpu_state.pc); + if ((seg&3)>dpl || (CPL)>dpl) + { + pclog("Data seg fail - %04X:%08X %04X %i %04X\n",CS,cpu_state.pc,seg,dpl,segdat[2]); + x86gpf(NULL,seg&~3); +// x86abort("Data segment load - level too low!\n",seg&0xFFFC); + return; + } + break; + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + default: + pclog("Invalid segment type for %04X! %04X\n",seg&0xFFFC,segdat[2]); + x86gpf(NULL,seg&~3); + return; + } + } + + if (!(segdat[2] & 0x8000)) + { + x86np("Load data seg not present", seg & 0xfffc); + return; + } + s->seg = seg; + do_seg_load(s, segdat); + +#ifndef CS_ACCESSED + if (s != &_cs) + { +#endif +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif +#ifndef CS_ACCESSED + } +#endif + s->checked = 0; + } + else + { + s->access = (3 << 5) | 2 | 0x80; + s->base = seg << 4; + s->seg = seg; + if (s == &_ss) + stack32 = 0; + s->checked = 1; + } +} + +#define DPL ((segdat[2]>>13)&3) +#define DPL2 ((segdat2[2]>>13)&3) +#define DPL3 ((segdat3[2]>>13)&3) + +void loadcs(uint16_t seg) +{ + uint16_t segdat[4]; + uint32_t addr; + if (output) pclog("Load CS %04X\n",seg); + if (msw&1 && !(eflags&VM_FLAG)) + { +// intcount++; +// flushmmucache(); +// pclog("Load CS %04X\n",seg); + if (!(seg&~3)) + { + pclog("Trying to load CS with NULL selector! lcs\n"); +// dumpregs(); +// exit(-1); + x86gpf(NULL,0); + return; + } +// pclog("Protected mode CS load! %04X\n",seg); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",seg,ldt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (optype==JMP) pclog("Code seg - %04X - %04X %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2],segdat[3]); +// if (!(segdat[2]&0x8000)) x86abort("Code segment not present!\n"); +// if (output) pclog("Segdat2 %04X\n",segdat[2]); + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf(NULL,seg&~3); + pclog("loadcs RPL > CPL %04X %04X %i %02X\n",segdat[2],seg,CPL,opcode); + return; + } + if (CPL != DPL) + { + x86gpf("loadcs(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcs(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS not present", seg & 0xfffc); + return; + } + if (segdat[3]&0x40) use32=0x300; + else use32=0; + CS=(seg&~3)|CPL; + do_seg_load(&_cs, segdat); + use32=(segdat[3]&0x40)?0x300:0; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif +// if (output) pclog("Load CS %08X\n",_cs.base); +// CS=(CS&0xFFFC)|((_cs.access>>5)&3); + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS system seg not present\n", seg & 0xfffc); + return; + } + switch (segdat[2]&0xF00) + { + default: + pclog("Bad CS %02X %02X %i special descriptor %03X %04X\n",opcode,rmdat,optype,segdat[2]&0xF00,seg); + x86gpf(NULL,seg&~3); + return; + } + } +// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); +// dumpregs(); +// exit(-1); + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; + else _cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + } +} + +void loadcsjmp(uint16_t seg, uint32_t oxpc) +{ + uint16_t segdat[4]; + uint32_t addr; + int count; + uint16_t type,seg2; + uint32_t newpc; +// pclog("Load CS JMP %04X\n",seg); + if (msw&1 && !(eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + pclog("Trying to load CS with NULL selector! lcsjmp\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",seg,ldt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (output) pclog("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + if (segdat[2]&0x1000) /*Normal code segment*/ + { +// pclog("Normal CS\n"); + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf("loadcsjmp(): segment PL > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf("loadcsjmp(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcsjmp(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP not present\n", seg & 0xfffc); + return; + } + if (segdat[3]&0x40) use32=0x300; + else use32=0; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + cycles -= timing_jmp_pm; + } + else /*System segment*/ + { +// pclog("System CS\n"); + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP system selector not present\n", seg & 0xfffc); + return; + } + type=segdat[2]&0xF00; + if (type==0x400) newpc=segdat[0]; + else newpc=segdat[0]|(segdat[3]<<16); + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: +// pclog("Call gate\n"); + cgate32=(type&0x800); + cgate16=!cgate32; + oldcs=CS; + oldpc=cpu_state.pc; + count=segdat[2]&31; +#if 0 + if ((DPL < CPL) || (DPL < (seg&3))) + { + x86gpf(NULL,seg&~3); + return; + } +#endif + if (DPL < CPL) + { + x86gpf("loadcsjmp(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcsjmp(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + if (!(seg2&~3)) + { + pclog("Trying to load CS with NULL selector! lcsjmpcg\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CSJ\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSJ\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + + if (DPL > CPL) + { + x86gpf("loadcsjmp(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP from call gate not present\n", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL > CPL) + { + pclog("Call gate DPL > CPL"); + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + CS=seg2; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + break; + + default: + pclog("JMP Call gate bad segment type\n"); + x86gpf(NULL,seg2&~3); + return; + } + cycles -= timing_jmp_pm_gate; + break; + + + case 0x900: /*386 Task gate*/ +// pclog("Task gate\n"); + cpu_state.pc=oxpc; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + flags &= ~NT_FLAG; + cpl_override=0; +// case 0xB00: /*386 Busy task gate*/ +// if (optype==JMP) pclog("Task switch!\n"); +// taskswitch386(seg,segdat); + return; + + default: + pclog("Bad JMP CS %02X %02X %i special descriptor %03X %04X\n",opcode,rmdat,optype,segdat[2]&0xF00,seg); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + } +// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); +// dumpregs(); +// exit(-1); + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; + else _cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + cycles -= timing_jmp_rm; + } +} + +void PUSHW(uint16_t v) +{ +// if (output==3) pclog("PUSHW %04X to %08X\n",v,ESP-4); + if (stack32) + { + writememw(ss,ESP-2,v); + if (abrt) return; + ESP-=2; + } + else + { +// pclog("Write %04X to %08X\n", v, ss+((SP-2)&0xFFFF)); + writememw(ss,((SP-2)&0xFFFF),v); + if (abrt) return; + SP-=2; + } +} +void PUSHL(uint32_t v) +{ +// if (output==3) pclog("PUSHL %08X to %08X\n",v,ESP-4); + if (stack32) + { + writememl(ss,ESP-4,v); + if (abrt) return; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),v); + if (abrt) return; + SP-=4; + } +} +uint16_t POPW() +{ + uint16_t tempw; + if (stack32) + { + tempw=readmemw(ss,ESP); + if (abrt) return 0; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); + if (abrt) return 0; + SP+=2; + } + return tempw; +} +uint32_t POPL() +{ + uint32_t templ; + if (stack32) + { + templ=readmeml(ss,ESP); + if (abrt) return 0; + ESP+=4; + } + else + { + templ=readmeml(ss,SP); + if (abrt) return 0; + SP+=4; + } + return templ; +} + +void loadcscall(uint16_t seg) +{ + uint16_t seg2; + uint16_t segdat[4],segdat2[4],newss; + uint32_t addr,oldssbase=ss, oaddr; + uint32_t newpc; + int count; + uint16_t oldcs=CPL; + uint32_t oldss,oldsp,newsp,oldpc, oldsp2; + int type; + uint16_t tempw; + + int csout = output; + + if (msw&1 && !(eflags&VM_FLAG)) + { + //flushmmucache(); + if (csout) pclog("Protected mode CS load! %04X\n",seg); + if (!(seg&~3)) + { + pclog("Trying to load CS with NULL selector! lcscall\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CSC\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSC\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + type=segdat[2]&0xF00; + if (type==0x400) newpc=segdat[0]; + else newpc=segdat[0]|(segdat[3]<<16); + + if (csout) pclog("Code seg call - %04X - %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2]); + if (segdat[2]&0x1000) + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + /* if (csout) */ pclog("Not conforming, RPL > CPL\n"); + x86gpf("loadcscall(): segment > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + /* if (csout) */ pclog("Not conforming, CPL != DPL (%i %i)\n",CPL,DPL); + x86gpf(NULL,seg&~3); + return; + } + } + if (CPL < DPL) + { + /* if (csout) */ pclog("CPL < DPL\n"); + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + /* if (csout) */ pclog("Not present\n"); + x86np("Load CS call not present", seg & 0xfffc); + return; + } + if (segdat[3]&0x40) use32=0x300; + else use32=0; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + /*Conforming segments don't change CPL, so preserve existing CPL*/ + if (segdat[2]&0x400) + { + seg = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + } + else /*On non-conforming segments, set RPL = CPL*/ + seg = (seg & ~3) | CPL; + CS=seg; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + if (csout) pclog("Complete\n"); + cycles -= timing_call_pm; + } + else + { + type=segdat[2]&0xF00; + if (csout) pclog("Type %03X\n",type); + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: /*386 Call gate*/ + if (output) pclog("Callgate %08X\n", cpu_state.pc); + cgate32=(type&0x800); + cgate16=!cgate32; + oldcs=CS; + oldpc=cpu_state.pc; + count=segdat[2]&31; +#if 0 + if ((DPL < CPL) || (DPL < (seg&3))) + { + x86gpf("",seg&~3); + return; + } +#endif + if ((DPL < CPL)) + { + x86gpf("loadcscall(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcscall(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + if (output) pclog("Call gate not present %04X\n",seg); + x86np("Call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + if (output) pclog("New address : %04X:%08X\n", seg2, newpc); + + if (!(seg2&~3)) + { + pclog("Trying to load CS with NULL selector! lcscallcg\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CSC\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSC\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + + if (output) pclog("Code seg2 call - %04X - %04X %04X %04X\n",seg2,segdat[0],segdat[1],segdat[2]); + + if (DPL > CPL) + { + x86gpf("loadcscall(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + if (output) pclog("Call gate CS not present %04X\n",seg2); + x86np("Call gate CS not present", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL < CPL) + { + oaddr = addr; + /*Load new stack*/ + oldss=SS; + oldsp=oldsp2=ESP; + cpl_override=1; + if (tr.access&8) + { + addr = 4 + tr.base + (DPL * 8); + newss=readmemw(0,addr+4); + newsp=readmeml(0,addr); + } + else + { + addr = 2 + tr.base + (DPL * 4); + newss=readmemw(0,addr+2); + newsp=readmemw(0,addr); + } + cpl_override=0; + if (abrt) return; + if (output) pclog("New stack %04X:%08X\n",newss,newsp); + if (!(newss&~3)) + { + pclog("Call gate loading null SS\n"); + x86ts(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + if (output) pclog("Read stack seg\n"); + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (output) pclog("Read stack seg done!\n"); + if (((newss & 3) != DPL) || (DPL2 != DPL)) + { + pclog("Call gate loading SS with wrong permissions %04X %04X %i %i %04X %04X\n", newss, seg2, DPL, DPL2, segdat[2], segdat2[2]); +// dumpregs(); +// exit(-1); + x86ts(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + pclog("Call gate loading SS wrong type\n"); + x86ts(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + pclog("Call gate loading SS not present\n"); + x86np("Call gate loading SS not present\n", newss & 0xfffc); + return; + } + if (!stack32) oldsp &= 0xFFFF; + SS=newss; + stack32 = (segdat2[3] & 0x40) ? 1 : 0; + if (stack32) ESP=newsp; + else SP=newsp; + + do_seg_load(&_ss, segdat2); + + if (output) pclog("Set access 1\n"); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS=seg2; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + cpu_state.pc=newpc; + + if (output) pclog("Set access 2\n"); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + if (output) pclog("Type %04X\n",type); + if (type==0xC00) + { + PUSHL(oldss); + PUSHL(oldsp2); + if (abrt) + { + pclog("ABRT PUSHL\n"); + SS = oldss; + ESP = oldsp2; + return; + } +// if (output) pclog("Stack now %04X:%08X\n",SS,ESP); + if (count) + { + while (count) + { + count--; + PUSHL(readmeml(oldssbase,oldsp+(count*4))); + if (abrt) + { + pclog("ABRT COPYL\n"); + SS = oldss; + ESP = oldsp2; + return; + } + } + } +// x86abort("Call gate with count %i\n",count); +// PUSHL(oldcs); +// PUSHL(oldpc); if (abrt) return; + } + else + { + if (output) pclog("Stack %04X\n",SP); + PUSHW(oldss); + if (output) pclog("Write SS to %04X:%04X\n",SS,SP); + PUSHW(oldsp2); + if (abrt) + { + pclog("ABRT PUSHW\n"); + SS = oldss; + ESP = oldsp2; + return; + } + if (output) pclog("Write SP to %04X:%04X\n",SS,SP); +// if (output) pclog("Stack %04X %i %04X:%04X\n",SP,count,oldssbase,oldsp); +// if (output) pclog("PUSH %04X %04X %i %i now %04X:%08X\n",oldss,oldsp,count,stack32,SS,ESP); + if (count) + { + while (count) + { + count--; + tempw=readmemw(oldssbase,(oldsp&0xFFFF)+(count*2)); + if (output) pclog("PUSH %04X\n",tempw); + PUSHW(tempw); + if (abrt) + { + pclog("ABRT COPYW\n"); + SS = oldss; + ESP = oldsp2; + return; + } + } + } +// if (output) pclog("Stack %04X\n",SP); +// if (count) x86abort("Call gate with count\n"); +// PUSHW(oldcs); +// PUSHW(oldpc); if (abrt) return; + } + cycles -= timing_call_pm_gate_inner; + break; + } + else if (DPL > CPL) + { + pclog("Call gate DPL > CPL"); + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ +/* if (type==0xC00) + { + PUSHL(oldcs); + PUSHL(oldpc); if (abrt) return; + } + else + { + PUSHW(oldcs); + PUSHW(oldpc); if (abrt) return; + }*/ + CS=seg2; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_call_pm_gate; + break; + + default: + pclog("Call gate bad segment type\n"); + x86gpf(NULL,seg2&~3); + return; + } + break; + +// case 0x900: /*386 Task gate*/ +// case 0xB00: /*386 Busy task gate*/ +// if (optype==JMP) pclog("Task switch!\n"); +// taskswitch386(seg,segdat); +// return; + + + default: + pclog("Bad CALL special descriptor %03X\n",segdat[2]&0xF00); + x86gpf(NULL,seg&~3); + return; +// dumpregs(); +// exit(-1); + } + } +// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); +// dumpregs(); +// exit(-1); + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; + else _cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + } +} + +void pmoderetf(int is32, uint16_t off) +{ + uint32_t newpc; + uint32_t newsp; + uint32_t addr, oaddr; + uint16_t segdat[4],segdat2[4],seg,newss; + uint32_t oldsp=ESP; + if (output) pclog("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,eflags); + if (is32) + { + newpc=POPL(); + seg=POPL(); if (abrt) return; + } + else + { + if (output) pclog("PC read from %04X:%04X\n",SS,SP); + newpc=POPW(); + if (output) pclog("CS read from %04X:%04X\n",SS,SP); + seg=POPW(); if (abrt) return; + } + if (output) pclog("Return to %04X:%08X\n",seg,newpc); + if ((seg&3)=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X RETF\n",seg,ldt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X RETF\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); +// dumpregs(); +// exit(-1); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } + oaddr = addr; + + if (output) pclog("CPL %i RPL %i %i\n",CPL,seg&3,is32); + + if (stack32) ESP+=off; + else SP+=off; + + if (CPL==(seg&3)) + { + if (output) pclog("RETF CPL = RPL %04X\n", segdat[2]); + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (CPL != DPL) + { + pclog("RETF non-conforming CPL != DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (CPL < DPL) + { + pclog("RETF non-conforming CPL < DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + pclog("RETF CS not code segment\n"); + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("RETF CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + cpu_state.pc=newpc; + if (segdat[2] & 0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + CS = seg; + do_seg_load(&_cs, segdat); + _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + +// pclog("CPL=RPL return to %04X:%08X\n",CS,cpu_state.pc); + cycles -= timing_retf_pm; + } + else + { + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((seg&3) != DPL) + { + pclog("RETF non-conforming RPL != DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (output) pclog("RETF non-conforming, %i %i\n",seg&3, DPL); + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((seg&3) < DPL) + { + pclog("RETF non-conforming RPL < DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (output) pclog("RETF conforming, %i %i\n",seg&3, DPL); + break; + default: + pclog("RETF CS not code segment\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("RETF CS not present! %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); + + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + if (is32) + { + newsp=POPL(); + newss=POPL(); if (abrt) return; +// pclog("is32 new stack %04X:%04X\n",newss,newsp); + } + else + { + if (output) pclog("SP read from %04X:%04X\n",SS,SP); + newsp=POPW(); + if (output) pclog("SS read from %04X:%04X\n",SS,SP); + newss=POPW(); if (abrt) return; +// pclog("!is32 new stack %04X:%04X\n",newss,newsp); + } + if (output) pclog("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); + if (!(newss&~3)) + { + pclog("RETF loading null SS\n"); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X RETF SS\n",newss,gdt.limit); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X RETF SS\n",newss,gdt.limit); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } + if (output) pclog("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); +// if (((newss & 3) != DPL) || (DPL2 != DPL)) + if ((newss & 3) != (seg & 3)) + { + pclog("RETF loading SS with wrong permissions %i %i %04X %04X\n", newss & 3, seg & 3, newss, seg); + ESP=oldsp; +// output = 3; +// dumpregs(); +// exit(-1); + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + pclog("RETF loading SS wrong type\n"); + ESP=oldsp; +// dumpregs(); +// exit(-1); + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + pclog("RETF loading SS not present\n"); + ESP=oldsp; + x86np("RETF loading SS not present\n", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 3)) + { + pclog("RETF loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + SS=newss; + stack32 = (segdat2[3] & 0x40) ? 1 : 0; + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + cpu_state.pc=newpc; + CS=seg; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + + if (stack32) ESP+=off; + else SP+=off; + + check_seg_valid(&_ds); + check_seg_valid(&_es); + check_seg_valid(&_fs); + check_seg_valid(&_gs); +// pclog("CPL=idt.limit) + { + if (num==8) + { + /*Triple fault - reset!*/ + pclog("Triple fault!\n"); +// output=1; + softresetx86(); + } + else if (num==0xD) + { + pclog("Double fault!\n"); + pmodeint(8,0); + } + else + { + pclog("INT out of range\n"); + x86gpf(NULL,(num*8)+2+(soft)?0:1); + } + if (output) pclog("addr >= IDT.limit\n"); + return; + } + addr+=idt.base; + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(2,addr); + segdat[2]=readmemw(4,addr); + segdat[3]=readmemw(6,addr); cpl_override=0; if (abrt) { pclog("Abrt reading from %08X\n",addr); return; } + oaddr = addr; + + if (output) pclog("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); + if (!(segdat[2]&0x1F00)) + { + // pclog("No seg\n"); + x86gpf(NULL,(num*8)+2); + return; + } + if (DPL=0x800)?32:16; +// if (output) pclog("Int gate %04X %i oldpc %04X pc %04X\n",type,intgatesize,oldpc,cpu_state.pc); + if (!(segdat[2]&0x8000)) + { + pclog("Int gate not present\n"); + x86np("Int gate not present\n", (num << 3) | 2); + return; + } + seg=segdat[1]; + new_cpl = seg & 3; +// pclog("Interrupt gate : %04X:%04X%04X\n",seg,segdat[3],segdat[0]); + + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X INT\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X INT %i\n",seg,gdt.limit,ins); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } +/* if ((seg&3) < CPL) + { + pclog("INT to higher level\n"); + x86gpf(NULL,seg&~3); + return; + }*/ + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + oaddr = addr; + + if (DPL2 > CPL) + { + pclog("INT to higher level 2\n"); + x86gpf(NULL,seg&~3); + return; + } + //pclog("Type %04X\n",segdat2[2]); + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (DPL2=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X PMODEINT SS\n",newss,gdt.limit); + x86ss(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); + x86ss(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat3[0]=readmemw(0,addr); + segdat3[1]=readmemw(0,addr+2); + segdat3[2]=readmemw(0,addr+4); + segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (((newss & 3) != DPL2) || (DPL3 != DPL2)) + { + pclog("Int gate loading SS with wrong permissions\n"); + x86ss(NULL,newss&~3); + return; + } + if ((segdat3[2]&0x1A00)!=0x1200) + { + pclog("Int gate loading SS wrong type\n"); + x86ss(NULL,newss&~3); + return; + } + if (!(segdat3[2]&0x8000)) + { + pclog("Int gate loading SS not present\n"); + x86np("Int gate loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + stack32 = (segdat3[3] & 0x40) ? 1 : 0; + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&_ss, segdat3); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat3[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + if (output) pclog("New stack %04X:%08X\n",SS,ESP); + cpl_override=1; + if (type>=0x800) + { +// if (output) pclog("Push 32 %i\n",eflags&VM_FLAG); + if (eflags & VM_FLAG) + { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); if (abrt) return; + loadseg(0,&_ds); + loadseg(0,&_es); + loadseg(0,&_fs); + loadseg(0,&_gs); + } + PUSHL(oldss); + PUSHL(oldsp); + PUSHL(flags|(eflags<<16)); +// if (soft) pclog("Pushl CS %08X\n", CS); + PUSHL(CS); +// if (soft) pclog("Pushl PC %08X\n", cpu_state.pc); + PUSHL(cpu_state.pc); if (abrt) return; +// if (output) pclog("32Stack %04X:%08X\n",SS,ESP); + } + else + { +// if (output) pclog("Push 16\n"); + PUSHW(oldss); + PUSHW(oldsp); + PUSHW(flags); +// if (soft) pclog("Pushw CS %04X\n", CS); + PUSHW(CS); +// if (soft) pclog("Pushw pc %04X\n", cpu_state.pc); + PUSHW(cpu_state.pc); if (abrt) return; +// if (output) pclog("16Stack %04X:%08X\n",SS,ESP); + } + cpl_override=0; + _cs.access=0 | 0x80; + cycles -= timing_int_pm_outer - timing_int_pm; +// pclog("Non-confirming int gate, CS = %04X\n"); + break; + } + else if (DPL2!=CPL) + { + pclog("Non-conforming int gate DPL != CPL\n"); + x86gpf(NULL,seg&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (!(segdat2[2]&0x8000)) + { + pclog("Int gate CS not present\n"); + x86np("Int gate CS not present\n", segdat[1] & 0xfffc); + return; + } + if ((eflags & VM_FLAG) && DPL20x800) + { + PUSHL(flags|(eflags<<16)); +// if (soft) pclog("Pushlc CS %08X\n", CS); + PUSHL(CS); +// if (soft) pclog("Pushlc PC %08X\n", cpu_state.pc); + PUSHL(cpu_state.pc); if (abrt) return; + } + else + { + PUSHW(flags); +// if (soft) pclog("Pushwc CS %04X\n", CS); + PUSHW(CS); +// if (soft) pclog("Pushwc PC %04X\n", cpu_state.pc); + PUSHW(cpu_state.pc); if (abrt) return; + } + new_cpl = CS & 3; + break; + default: + pclog("Int gate CS not code segment - %04X %04X %04X %04X\n",segdat2[0],segdat2[1],segdat2[2],segdat2[3]); + x86gpf(NULL,seg&~3); + return; + } + do_seg_load(&_cs, segdat2); + CS = (seg & ~3) | new_cpl; + _cs.access = (_cs.access & ~(3 << 5)) | (new_cpl << 5); +// pclog("New CS = %04X\n",CS); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); + else cpu_state.pc=segdat[0]; + use32=(segdat2[3]&0x40)?0x300:0; +// pclog("Int gate done!\n"); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + eflags&=~VM_FLAG; + if (!(type&0x100)) + { + flags&=~I_FLAG; +// pclog("INT %02X disabling interrupts %i\n",num,soft); + } + flags&=~(T_FLAG|NT_FLAG); +// if (output) pclog("Final Stack %04X:%08X\n",SS,ESP); + cycles -= timing_int_pm; + break; + + case 0x500: /*Task gate*/ +// pclog("Task gate\n"); + seg=segdat[1]; + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X INT\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X INT %i\n",seg,gdt.limit,ins); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + cpl_override=0; if (abrt) return; + if (!(segdat2[2]&0x8000)) + { + pclog("Int task gate not present\n"); + x86np("Int task gate not present\n", segdat[1] & 0xfffc); + return; + } + optype=OPTYPE_INT; + cpl_override=1; + taskswitch286(seg,segdat2,segdat2[2]&0x800); + cpl_override=0; + break; + + default: + pclog("Bad int gate type %04X %04X %04X %04X %04X\n",segdat[2]&0x1F00,segdat[0],segdat[1],segdat[2],segdat[3]); + x86gpf(NULL,seg&~3); + return; + } +} + +void pmodeiret(int is32) +{ + uint32_t newsp; + uint16_t newss; + uint32_t tempflags,flagmask; + uint32_t newpc; + uint16_t segdat[4],segdat2[4]; + uint16_t segs[4]; + uint16_t seg; + uint32_t addr, oaddr; + uint32_t oldsp=ESP; + if (is386 && (eflags&VM_FLAG)) + { +// if (output) pclog("V86 IRET\n"); + if (IOPL!=3) + { + pclog("V86 IRET! IOPL!=3\n"); + x86gpf(NULL,0); + return; + } + oxpc=cpu_state.pc; + if (is32) + { + newpc=POPL(); + seg=POPL(); + tempflags=POPL(); if (abrt) return; + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (abrt) return; + } + cpu_state.pc=newpc; + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + _cs.access |= 0x80; + CS=seg; + flags=(flags&0x3000)|(tempflags&0xCFD5)|2; + cycles -= timing_iret_rm; + return; + } + +// pclog("IRET %i\n",is32); + //flushmmucache(); +// if (output) pclog("Pmode IRET %04X:%04X ",CS,cpu_state.pc); + + if (flags&NT_FLAG) + { +// pclog("NT IRET\n"); + seg=readmemw(tr.base,0); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("TS Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("TS Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); + taskswitch286(seg,segdat,0); + cpl_override=0; + return; + } + oxpc=cpu_state.pc; + flagmask=0xFFFF; + if (CPL) flagmask&=~0x3000; + if (IOPL>16)&VM_FLAG)) + { +// pclog("IRETD to V86\n"); + + newsp=POPL(); + newss=POPL(); + segs[0]=POPL(); + segs[1]=POPL(); + segs[2]=POPL(); + segs[3]=POPL(); if (abrt) { ESP = oldsp; return; } +// pclog("Pop stack %04X:%04X\n",newss,newsp); + eflags=tempflags>>16; + loadseg(segs[0],&_es); + do_seg_v86_init(&_es); + loadseg(segs[1],&_ds); + do_seg_v86_init(&_ds); + loadseg(segs[2],&_fs); + do_seg_v86_init(&_fs); + loadseg(segs[3],&_gs); + do_seg_v86_init(&_gs); + +// pclog("V86 IRET %04X:%08X\n",SS,ESP); +// output=3; + + cpu_state.pc=newpc; + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + _cs.access=(3<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + + ESP=newsp; + loadseg(newss,&_ss); + do_seg_v86_init(&_ss); + use32=0; + flags=(tempflags&0xFFD5)|2; + cycles -= timing_iret_v86; +// pclog("V86 IRET to %04X:%04X %04X:%04X %04X %04X %04X %04X %i\n",CS,cpu_state.pc,SS,SP,DS,ES,FS,GS,abrt); + // if (CS==0xFFFF && pc==0xFFFFFFFF) timetolive=12; +/* { + dumpregs(); + exit(-1); + }*/ + return; + } + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (abrt) { ESP = oldsp; return; } + } +// if (!is386) tempflags&=0xFFF; +// pclog("Returned to %04X:%08X %04X %04X %i\n",seg,newpc,flags,tempflags, ins); + if (!(seg&~3)) + { + pclog("IRET CS=0\n"); + ESP = oldsp; +// dumpregs(); +// exit(-1); + x86gpf(NULL,0); + return; + } + +// if (output) pclog("IRET %04X:%08X\n",seg,newpc); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit); + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit); + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + if ((seg&3) < CPL) + { + pclog("IRET to lower level\n"); + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP = oldsp; return; } +// pclog("Seg type %04X %04X\n",segdat[2]&0x1F00,segdat[2]); + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if ((seg&3) != DPL) + { + pclog("IRET NC DPL %04X %04X %04X %04X %04X\n", seg, segdat[0], segdat[1], segdat[2], segdat[3]); + ESP = oldsp; +// dumpregs(); +// exit(-1); + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ + if ((seg&3) < DPL) + { + pclog("IRET C DPL\n"); + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + pclog("IRET CS != code seg\n"); + ESP = oldsp; + x86gpf(NULL,seg&~3); +// dumpregs(); +// exit(-1); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("IRET CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); + ESP = oldsp; + x86np("IRET CS not present\n", seg & 0xfffc); + return; + } +// pclog("Seg %04X CPL %04X\n",seg,CPL); + if ((seg&3) == CPL) + { +// pclog("Same level\n"); + CS=seg; + do_seg_load(&_cs, segdat); + _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_iret_pm; + } + else /*Return to outer level*/ + { + oaddr = addr; + if (output) pclog("Outer level\n"); + if (is32) + { + newsp=POPL(); + newss=POPL(); if (abrt) { ESP = oldsp; return; } + } + else + { + newsp=POPW(); + newss=POPW(); if (abrt) { ESP = oldsp; return; } + } + + if (output) pclog("IRET load stack %04X:%04X\n",newss,newsp); + + if (!(newss&~3)) + { + pclog("IRET loading null SS\n"); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X PMODEIRET SS\n",newss,gdt.limit); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X PMODEIRET\n",newss,gdt.limit); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP = oldsp; return; } +// pclog("IRET SS sd2 %04X\n",segdat2[2]); +// if (((newss & 3) != DPL) || (DPL2 != DPL)) + if ((newss & 3) != (seg & 3)) + { + pclog("IRET loading SS with wrong permissions %04X %04X\n", newss, seg); + ESP = oldsp; +// dumpregs(); +// exit(-1); + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + pclog("IRET loading SS wrong type\n"); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (DPL2 != (seg & 3)) + { + pclog("IRET loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + pclog("IRET loading SS not present\n"); + ESP = oldsp; + x86np("IRET loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + stack32 = (segdat2[3] & 0x40) ? 1 : 0; + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + CS=seg; + do_seg_load(&_cs, segdat); + _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + + check_seg_valid(&_ds); + check_seg_valid(&_es); + check_seg_valid(&_fs); + check_seg_valid(&_gs); + cycles -= timing_iret_pm_outer; + } + cpu_state.pc=newpc; + flags=(flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2; + if (is32) eflags=tempflags>>16; +// pclog("done\n"); +} + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) +{ + uint32_t base; + uint32_t limit; + uint32_t templ; + uint16_t tempw; + + uint32_t new_cr3=0; + uint16_t new_es,new_cs,new_ss,new_ds,new_fs,new_gs; + uint16_t new_ldt; + + uint32_t new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi,new_pc,new_flags; + + uint32_t addr; + + uint16_t segdat2[4]; + +//output=3; + base=segdat[1]|((segdat[2]&0xFF)<<16)|((segdat[3]>>8)<<24); + limit=segdat[0]|((segdat[3]&0xF)<<16); +// pclog("286 Task switch! %04X:%04X\n",CS,cpu_state.pc); +/// pclog("TSS %04X base %08X limit %04X old TSS %04X %08X %i\n",seg,base,limit,tr.seg,tr.base,ins); +// / pclog("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + + if (is386) + { +// if (output) pclog("32-bit TSS\n"); + + new_cr3=readmeml(base,0x1C); + new_pc=readmeml(base,0x20); + new_flags=readmeml(base,0x24); + + new_eax=readmeml(base,0x28); + new_ecx=readmeml(base,0x2C); + new_edx=readmeml(base,0x30); + new_ebx=readmeml(base,0x34); + new_esp=readmeml(base,0x38); + new_ebp=readmeml(base,0x3C); + new_esi=readmeml(base,0x40); + new_edi=readmeml(base,0x44); + + new_es=readmemw(base,0x48); +// if (output) pclog("Read CS from %08X\n",base+0x4C); + new_cs=readmemw(base,0x4C); + new_ss=readmemw(base,0x50); + new_ds=readmemw(base,0x54); + new_fs=readmemw(base,0x58); + new_gs=readmemw(base,0x5C); + new_ldt=readmemw(base,0x60); + + if (abrt) return; + if (optype==JMP || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (abrt) return; + tempw&=~0x200; + if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); + else writememw(gdt.base,(tr.seg&~7)+4,tempw); + } + + if (optype==IRET) flags&=~NT_FLAG; + +// if (output) pclog("Write PC %08X %08X\n",tr.base,cpu_state.pc); + cpu_386_flags_rebuild(); + writememl(tr.base,0x1C,cr3); + writememl(tr.base,0x20,cpu_state.pc); + writememl(tr.base,0x24,flags|(eflags<<16)); + + writememl(tr.base,0x28,EAX); + writememl(tr.base,0x2C,ECX); + writememl(tr.base,0x30,EDX); + writememl(tr.base,0x34,EBX); + writememl(tr.base,0x38,ESP); + writememl(tr.base,0x3C,EBP); + writememl(tr.base,0x40,ESI); + writememl(tr.base,0x44,EDI); + + writememl(tr.base,0x48,ES); +// if (output) pclog("Write CS %04X to %08X\n",CS,tr.base+0x4C); + writememl(tr.base,0x4C,CS); + writememl(tr.base,0x50,SS); + writememl(tr.base,0x54,DS); + writememl(tr.base,0x58,FS); + writememl(tr.base,0x5C,GS); + writememl(tr.base,0x60,ldt.seg); + + if (optype==OPTYPE_INT) + { + writememl(base,0,tr.seg); + new_flags|=NT_FLAG; + } + if (abrt) return; + if (optype==JMP || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + + + + cr3=new_cr3; +// pclog("TS New CR3 %08X\n",cr3); + flushmmucache(); + + + + cpu_state.pc=new_pc; +// if (output) pclog("New pc %08X\n",new_pc); + flags=new_flags; + eflags=new_flags>>16; + cpu_386_flags_extract(); + +// if (output) pclog("Load LDT %04X\n",new_ldt); + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+gdt.base; +// if (output) pclog("Load from %08X %08X\n",templ,gdt.base); + ldt.limit=readmemw(0,templ); + if (readmemb(templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base=(readmemw(0,templ+2))|(readmemb(templ+4)<<16)|(readmemb(templ+7)<<24); +// if (output) pclog("Limit %04X Base %08X\n",ldt.limit,ldt.base); + + + if (eflags&VM_FLAG) + { + pclog("Task switch V86!\n"); + x86gpf(NULL,0); + return; + } + + if (!(new_cs&~3)) + { + pclog("TS loading null CS\n"); + x86gpf(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X %04X TS\n",new_cs,ldt.limit,addr); + x86gpf(NULL,0); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X TS\n",new_cs,gdt.limit); + x86gpf(NULL,0); + return; + } + addr+=gdt.base; + } + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + if (!(segdat2[2]&0x8000)) + { + pclog("TS loading CS not present\n"); + x86np("TS loading CS not present\n", new_cs & 0xfffc); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((new_cs&3) != DPL2) + { + pclog("TS load CS non-conforming RPL != DPL"); + x86gpf(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + pclog("TS load CS non-conforming RPL < DPL"); + x86gpf(NULL,new_cs&~3); + return; + } + break; + default: + pclog("TS load CS not code segment\n"); + x86gpf(NULL,new_cs&~3); + return; + } + +// if (output) pclog("new_cs %04X\n",new_cs); + CS=new_cs; + do_seg_load(&_cs, segdat2); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat2[3]&0x40)?0x300:0; + + EAX=new_eax; + ECX=new_ecx; + EDX=new_edx; + EBX=new_ebx; + ESP=new_esp; + EBP=new_ebp; + ESI=new_esi; + EDI=new_edi; + + if (output) pclog("Load ES %04X\n",new_es); + loadseg(new_es,&_es); + if (output) pclog("Load SS %04X\n",new_ss); + loadseg(new_ss,&_ss); + if (output) pclog("Load DS %04X\n",new_ds); + loadseg(new_ds,&_ds); + if (output) pclog("Load FS %04X\n",new_fs); + loadseg(new_fs,&_fs); + if (output) pclog("Load GS %04X\n",new_gs); + loadseg(new_gs,&_gs); + + if (output) pclog("Resuming at %04X:%08X\n",CS,cpu_state.pc); + } + else + { + pclog("16-bit TSS\n"); + resetx86(); + //exit(-1); + } + + + tr.seg=seg; + tr.base=base; + tr.limit=limit; + tr.access=segdat[2]>>8; +} + diff --git a/src/x86seg.h b/src/x86seg.h new file mode 100644 index 000000000..daf10a46e --- /dev/null +++ b/src/x86seg.h @@ -0,0 +1 @@ +void do_seg_load(x86seg *s, uint16_t *segdat); diff --git a/src/x87.c b/src/x87.c new file mode 100644 index 000000000..277320383 --- /dev/null +++ b/src/x87.c @@ -0,0 +1,90 @@ +//Quake timedemo demo1 - 8.1FPS + +//11A00 - D_SCAlloc +//11C1C - D_CacheSurface + +//36174 - SCR_CalcRefdef + +//SCR_CalcRefdef +//Calls R_SetVrect and R_ViewChanged + +#define fplog 0 + +#include +#include "ibm.h" +#include "pic.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "386_common.h" + +double ST[8]; +uint64_t ST_i64[8]; +MMX_REG MM[8]; +int ismmx; +uint16_t npxs,npxc; +uint8_t tag[8]; + +int TOP; + +uint16_t x87_gettag() +{ + uint16_t ret = 0; + int c; + + for (c = 0; c < 8; c++) + { + if (tag[c] & TAG_UINT64) + ret |= 2 << (c*2); + else + ret |= (tag[c] << (c*2)); + } + + return ret; +} + +void x87_settag(uint16_t new_tag) +{ + tag[0] = new_tag & 3; + tag[1] = (new_tag >> 2) & 3; + tag[2] = (new_tag >> 4) & 3; + tag[3] = (new_tag >> 6) & 3; + tag[4] = (new_tag >> 8) & 3; + tag[5] = (new_tag >> 10) & 3; + tag[6] = (new_tag >> 12) & 3; + tag[7] = (new_tag >> 14) & 3; +} + +void x87_dumpregs() +{ + if (ismmx) + { + pclog("MM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\n", MM[0].q, MM[1].q, MM[2].q, MM[3].q); + pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", MM[4].q, MM[5].q, MM[6].q, MM[7].q); + } + else + { + pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",ST[TOP],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7]); + } + pclog("Status = %04X Control = %04X Tag = %04X\n",npxs,npxc,x87_gettag()); +} + +void x87_print() +{ + if (ismmx) + { + pclog("\tMM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\t", MM[0].q, MM[1].q, MM[2].q, MM[3].q); + pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", MM[4].q, MM[5].q, MM[6].q, MM[7].q); + } + else + { + pclog("\tST(0)=%.20f\tST(1)=%.20f\tST(2)=%f\tST(3)=%f\t",ST[TOP&7],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t TOP=%i CR=%04X SR=%04X TAG=%04X\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7], TOP, npxc, npxs, x87_gettag()); + } +} + +void x87_reset() +{ +} diff --git a/src/x87.h b/src/x87.h new file mode 100644 index 000000000..1c58ba189 --- /dev/null +++ b/src/x87.h @@ -0,0 +1,32 @@ +uint32_t x87_pc_off,x87_op_off; +uint16_t x87_pc_seg,x87_op_seg; +extern uint32_t op32; +extern int TOP; +extern uint16_t npxs, npxc; +extern uint8_t tag[8]; +extern int ismmx; +extern double ST[8]; +extern uint64_t ST_i64[8]; + +typedef union MMX_REG +{ + uint64_t q; + int64_t sq; + uint32_t l[2]; + int32_t sl[2]; + uint16_t w[5]; + int16_t sw[4]; + uint8_t b[8]; + int8_t sb[8]; +} MMX_REG; + +extern MMX_REG MM[8]; + +static inline void x87_set_mmx(); +static inline void x87_emms(); + +uint16_t x87_gettag(); +void x87_settag(uint16_t new_tag); + +/*Hack for FPU copy. If set then ST_i64 contains the 64-bit integer loaded by FILD*/ +#define TAG_UINT64 (1 << 2) diff --git a/src/x87_ops.h b/src/x87_ops.h new file mode 100644 index 000000000..6a1fadca3 --- /dev/null +++ b/src/x87_ops.h @@ -0,0 +1,1127 @@ +#include +#include + +#define fplog 0 + +static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}; + +#define ST(x) ST[((TOP+(x))&7)] + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +#define STATUS_ZERODIVIDE 4 + +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + npxs |= STATUS_ZERODIVIDE; \ + if (npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + pclog("FPU : divide by zero\n"); \ + picint(1 << 13); \ + } \ + return 1; \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) + +static inline void x87_set_mmx() +{ + TOP = 0; + *(uint64_t *)tag = 0; + ismmx = 1; +} + +static inline void x87_emms() +{ + *tag = 0x0303030303030303ll; + ismmx = 0; +} + +static inline void x87_checkexceptions() +{ +} + +static inline void x87_push(double i) +{ + TOP=(TOP-1)&7; + ST[TOP]=i; + tag[TOP&7] = (i == 0.0) ? 1 : 0; +} + +static inline double x87_pop() +{ + double t=ST[TOP]; + tag[TOP&7] = 3; + TOP=(TOP+1)&7; + return t; +} + +static inline int64_t x87_fround(double b) +{ + int64_t a, c; + + switch ((npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } +} +#define BIAS80 16383 +#define BIAS64 1023 + +static inline double x87_ld80() +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + test.eind.ll = readmeml(easeg,eaaddr); + test.eind.ll |= (uint64_t)readmeml(easeg,eaaddr+4)<<32; + test.begin = readmemw(easeg,eaaddr+8); + + int64_t exp64 = (((test.begin&0x7fff) - BIAS80)); + int64_t blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + int64_t exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + int64_t mant64 = (test.eind.ll >> 11) & (0xfffffffffffff); + int64_t sign = (test.begin&0x8000)?1:0; + + if ((test.begin & 0x7fff) == 0x7fff) + exp64final = 0x7ff; + if ((test.begin & 0x7fff) == 0) + exp64final = 0; + if (test.eind.ll & 0x400) + mant64++; + + test.eind.ll = (sign <<63)|(exp64final << 52)| mant64; + + return test.eind.d; +} + +static inline void x87_st80(double d) +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + + test.eind.d=d; + + int64_t sign80 = (test.eind.ll&(0x8000000000000000))?1:0; + int64_t exp80 = test.eind.ll&(0x7ff0000000000000); + int64_t exp80final = (exp80>>52); + int64_t mant80 = test.eind.ll&(0x000fffffffffffff); + int64_t mant80final = (mant80 << 11); + + if (exp80final == 0x7ff) /*Infinity / Nan*/ + { + exp80final = 0x7fff; + mant80final |= (0x8000000000000000); + } + else if (d != 0){ //Zero is a special case + // Elvira wants the 8 and tcalc doesn't + mant80final |= (0x8000000000000000); + //Ca-cyber doesn't like this when result is zero. + exp80final += (BIAS80 - BIAS64); + } + test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; + test.eind.ll = mant80final; + + writememl(easeg,eaaddr,test.eind.ll); + writememl(easeg,eaaddr+4,test.eind.ll>>32); + writememw(easeg,eaaddr+8,test.begin); +} + +static inline void x87_st_fsave(int reg) +{ + reg = (TOP + reg) & 7; + + if (tag[reg] & TAG_UINT64) + { + writememl(easeg, eaaddr, ST_i64[reg] & 0xffffffff); + writememl(easeg, eaaddr + 4, ST_i64[reg] >> 32); + writememw(easeg, eaaddr + 8, 0x5555); + } + else + x87_st80(ST[reg]); +} + +static inline void x87_ld_frstor(int reg) +{ + uint16_t temp; + + reg = (TOP + reg) & 7; + + temp = readmemw(easeg, eaaddr + 8); + + if (temp == 0x5555 && tag[reg] == 2) + { + tag[reg] = TAG_UINT64; + ST_i64[reg] = readmeml(easeg, eaaddr); + ST_i64[reg] |= ((uint64_t)readmeml(easeg, eaaddr + 4) << 32); + ST[reg] = (double)ST_i64[reg]; + } + else + ST[reg] = x87_ld80(); +} + +static inline void x87_ldmmx(MMX_REG *r) +{ + r->l[0] = readmeml(easeg, eaaddr); + r->l[1] = readmeml(easeg, eaaddr + 4); + r->w[4] = readmemw(easeg, eaaddr + 8); +} + +static inline void x87_stmmx(MMX_REG r) +{ + writememl(easeg, eaaddr, r.l[0]); + writememl(easeg, eaaddr + 4, r.l[1]); + writememw(easeg, eaaddr + 8, 0xffff); +} + +static inline uint16_t x87_compare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + uint32_t out; + + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + asm volatile ("" : : : "memory"); + + asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fcompp\n" + "fnstsw %0\n" + : "=m" (out) + : "m" (a), "m" (b) + ); + + return out & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t out = 0; + + if (a == b) + out |= C3; + else if (a < b) + out |= C0; + + return out; +#endif +} + +static inline uint16_t x87_ucompare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + uint32_t out; + + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + asm volatile ("" : : : "memory"); + + asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fucompp\n" + "fnstsw %0\n" + : "=m" (out) + : "m" (a), "m" (b) + ); + + return out & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t out = 0; + + if (a == b) + out |= C3; + else if (a < b) + out |= C0; + + return out; +#endif +} + +typedef union +{ + float s; + uint32_t i; +} x87_ts; + +typedef union +{ + double d; + uint64_t i; +} x87_td; + +#define FP_ENTER() do \ + { \ + flags_rebuild(); \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + fpucount++; \ + } while (0) + +#include "x87_ops_arith.h" +#include "x87_ops_misc.h" +#include "x87_ops_loadstore.h" + +static int op_nofpu_a16(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + fetch_ea_16(fetchdat); +} +static int op_nofpu_a32(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + fetch_ea_32(fetchdat); +} + +OpFn OP_TABLE(fpu_d8_a16)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; +OpFn OP_TABLE(fpu_d8_a32)[32] = +{ + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +OpFn OP_TABLE(fpu_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL, ILLEGAL, opFTST, opFXAM, ILLEGAL, ILLEGAL, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1,opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +OpFn OP_TABLE(fpu_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL, ILLEGAL, opFTST, opFXAM, ILLEGAL, ILLEGAL, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1,opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +OpFn OP_TABLE(fpu_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_686_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_686_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_686_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_686_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +OpFn OP_TABLE(fpu_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +OpFn OP_TABLE(fpu_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +OpFn OP_TABLE(fpu_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +OpFn OP_TABLE(fpu_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_686_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_686_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(nofpu_a16)[256] = +{ + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, +}; +OpFn OP_TABLE(nofpu_a32)[256] = +{ + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, +}; diff --git a/src/x87_ops_arith.h b/src/x87_ops_arith.h new file mode 100644 index 000000000..6e8fb4659 --- /dev/null +++ b/src/x87_ops_arith.h @@ -0,0 +1,428 @@ +#define opFPU(name, optype, a_size, load_var, get, use_var) \ +static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + if ((npxc >> 10) & 3) \ + fesetround(rounding_modes[(npxc >> 10) & 3]); \ + ST(0) += use_var; \ + if ((npxc >> 10) & 3) \ + fesetround(FE_TONEAREST); \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + npxs &= ~(C0|C2|C3); \ + npxs |= x87_compare(ST(0), (double)use_var); \ + CLOCK_CYCLES(4); \ + return 0; \ +} \ +static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + npxs &= ~(C0|C2|C3); \ + npxs |= x87_compare(ST(0), (double)use_var); \ + x87_pop(); \ + CLOCK_CYCLES(4); \ + return 0; \ +} \ +static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + x87_div(ST(0), ST(0), use_var); \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + x87_div(ST(0), use_var, ST(0)); \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + ST(0) *= use_var; \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(11); \ + return 0; \ +} \ +static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + ST(0) -= use_var; \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + ST(0) = use_var - ST(0); \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(8); \ + return 0; \ +} + + +opFPU(s, x87_ts, 16, t.i, geteal, t.s) +opFPU(s, x87_ts, 32, t.i, geteal, t.s) +opFPU(d, x87_td, 16, t.i, geteaq, t.d) +opFPU(d, x87_td, 32, t.i, geteaq, t.d) + +opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t) +opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t) +opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t) +opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t) + + + + +static int opFADD(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FADD\n"); + ST(0) = ST(0) + ST(fetchdat & 7); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FADD\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FADDP\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOM\n"); + npxs &= ~(C0|C2|C3); + if (ST(0) == ST(fetchdat & 7)) npxs |= C3; + else if (ST(0) < ST(fetchdat & 7)) npxs |= C0; + CLOCK_CYCLES(4); + return 0; +} + +static int opFCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOMP\n"); + npxs &= ~(C0|C2|C3); + npxs |= x87_compare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFCOMPP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOMPP\n"); + npxs &= ~(C0|C2|C3); + if (*(uint64_t *)&ST(0) == ((uint64_t)1 << 63) && *(uint64_t *)&ST(1) == 0) + npxs |= C0; /*Nasty hack to fix 80387 detection*/ + else + npxs |= x87_compare(ST(0), ST(1)); + + x87_pop(); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} +static int opFUCOMPP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMPP\n", easeg, eaaddr); + npxs &= ~(C0|C2|C3); + npxs |= x87_ucompare(ST(0), ST(1)); + x87_pop(); + x87_pop(); + CLOCK_CYCLES(5); + return 0; +} + +static int opFCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FICOM\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + CLOCK_CYCLES(4); + return 0; +} +static int opFCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FICOMP\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFDIV(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIV\n"); + x87_div(ST(0), ST(0), ST(fetchdat & 7)); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIV\n"); + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVP\n"); + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFDIVR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVR\n"); + x87_div(ST(0), ST(fetchdat&7), ST(0)); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVR\n"); + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVR\n"); + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFMUL(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FMUL\n"); + ST(0) = ST(0) * ST(fetchdat & 7); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FMUL\n"); + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FMULP\n"); + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(16); + return 0; +} + +static int opFSUB(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUB\n"); + ST(0) = ST(0) - ST(fetchdat & 7); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUB\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBP\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFSUBR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBR\n"); + ST(0) = ST(fetchdat & 7) - ST(0); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBR\n"); + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBRP\n"); + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFUCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOM\n"); + npxs &= ~(C0|C2|C3); + npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMP\n"); + npxs &= ~(C0|C2|C3); + npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMI\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + CLOCK_CYCLES(4); + return 0; +} +static int opFUCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMIP\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} diff --git a/src/x87_ops_loadstore.h b/src/x87_ops_loadstore.h new file mode 100644 index 000000000..bede280b9 --- /dev/null +++ b/src/x87_ops_loadstore.h @@ -0,0 +1,470 @@ +static int opFILDiw_a16(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FILDw %08X:%08X\n", easeg, eaaddr); + temp = geteaw(); if (abrt) return 1; + if (fplog) pclog(" %f\n", (double)temp); + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} +static int opFILDiw_a32(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FILDw %08X:%08X\n", easeg, eaaddr); + temp = geteaw(); if (abrt) return 1; + if (fplog) pclog(" %f\n", (double)temp); + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} + +static int opFISTiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return abrt; +} +static int opFISTiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return abrt; +} + +static int opFISTPiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +static int opFISTPiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} + +static int opFILDiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FILDl %08X:%08X\n", easeg, eaaddr); + temp64 = geteaq(); if (abrt) return 1; + if (fplog) pclog(" %f %08X %08X\n", (double)temp64, readmeml(easeg,eaaddr), readmeml(easeg,eaaddr+4)); + x87_push((double)temp64); + ST_i64[TOP] = temp64; + tag[TOP] |= TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} +static int opFILDiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FILDl %08X:%08X\n", easeg, eaaddr); + temp64 = geteaq(); if (abrt) return 1; + if (fplog) pclog(" %f %08X %08X\n", (double)temp64, readmeml(easeg,eaaddr), readmeml(easeg,eaaddr+4)); + x87_push((double)temp64); + ST_i64[TOP] = temp64; + tag[TOP] |= TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} + +static int FBSTP_a16(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FBSTP %08X:%08X\n", easeg, eaaddr); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, eaaddr + 9, tempc); if (abrt) return 1; + x87_pop(); + return 0; +} +static int FBSTP_a32(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FBSTP %08X:%08X\n", easeg, eaaddr); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, eaaddr + 9, tempc); if (abrt) return 1; + x87_pop(); + return 0; +} + +static int FISTPiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTPl %08X:%08X\n", easeg, eaaddr); + if (tag[TOP] & TAG_UINT64) + temp64 = ST_i64[TOP]; + else + temp64 = x87_fround(ST(0)); + seteaq(temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +static int FISTPiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTPl %08X:%08X\n", easeg, eaaddr); + if (tag[TOP] & TAG_UINT64) + temp64 = ST_i64[TOP]; + else + temp64 = x87_fround(ST(0)); + seteaq(temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} + +static int opFILDil_a16(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FILDs %08X:%08X\n", easeg, eaaddr); + templ = geteal(); if (abrt) return 1; + if (fplog) pclog(" %f %08X %i\n", (double)templ, templ, templ); + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} +static int opFILDil_a32(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FILDs %08X:%08X\n", easeg, eaaddr); + templ = geteal(); if (abrt) return 1; + if (fplog) pclog(" %f %08X %i\n", (double)templ, templ, templ); + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} + +static int opFISTil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return abrt; +} +static int opFISTil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return abrt; +} + +static int opFISTPil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(28); + return 0; +} +static int opFISTPil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(28); + return 0; +} + +static int opFLDe_a16(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDe %08X:%08X\n", easeg, eaaddr); + t=x87_ld80(); if (abrt) return 1; + if (fplog) pclog(" %f\n", t); + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} +static int opFLDe_a32(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDe %08X:%08X\n", easeg, eaaddr); + t=x87_ld80(); if (abrt) return 1; + if (fplog) pclog(" %f\n", t); + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} + +static int opFSTPe_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTPe %08X:%08X\n", easeg, eaaddr); + x87_st80(ST(0)); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} +static int opFSTPe_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTPe %08X:%08X\n", easeg, eaaddr); + x87_st80(ST(0)); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} + +static int opFLDd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDd %08X:%08X\n", easeg, eaaddr); + t.i = geteaq(); if (abrt) return 1; + if (fplog) pclog(" %f\n", t.d); + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} +static int opFLDd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDd %08X:%08X\n", easeg, eaaddr); + t.i = geteaq(); if (abrt) return 1; + if (fplog) pclog(" %f\n", t.d); + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, eaaddr); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return abrt; +} +static int opFSTd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, eaaddr); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return abrt; +} + +static int opFSTPd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 7); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, eaaddr); + t.d = ST(0); + seteaq(t.i); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} +static int opFSTPd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 7); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, eaaddr); + t.d = ST(0); + seteaq(t.i); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDs %08X:%08X\n", easeg, eaaddr); + ts.i = geteal(); if (abrt) return 1; + if (fplog) pclog(" %f\n", ts.s); + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} +static int opFLDs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDs %08X:%08X\n", easeg, eaaddr); + ts.i = geteal(); if (abrt) return 1; + if (fplog) pclog(" %f\n", ts.s); + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return abrt; +} +static int opFSTs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return abrt; +} + +static int opFSTPs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} +static int opFSTPs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} diff --git a/src/x87_ops_misc.h b/src/x87_ops_misc.h new file mode 100644 index 000000000..401e84cc6 --- /dev/null +++ b/src/x87_ops_misc.h @@ -0,0 +1,828 @@ +static int opFSTSW_AX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSTSW\n"); + AX = npxs; + CLOCK_CYCLES(3); + return 0; +} + + + +static int opFNOP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + CLOCK_CYCLES(4); + return 0; +} + +static int opFCLEX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + npxs &= 0xff00; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINIT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + npxc = 0x37F; + npxs = 0; + *(uint64_t *)tag = 0x0303030303030303ll; + TOP = 0; + CLOCK_CYCLES(17); + return 0; +} + + +static int opFFREE(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FFREE\n"); + tag[(TOP + fetchdat) & 7] = 3; + CLOCK_CYCLES(3); + return 0; +} + +static int opFST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FST\n"); + ST(fetchdat & 7) = ST(0); + tag[(TOP + fetchdat) & 7] = tag[TOP & 7]; + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTP(uint32_t fetchdat) +{ + int temp; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSTP\n"); + ST(fetchdat & 7) = ST(0); + tag[(TOP + fetchdat) & 7] = tag[TOP & 7]; + x87_pop(); + CLOCK_CYCLES(3); + return 0; +} + + + + +static int FSTOR() +{ + FP_ENTER(); + switch ((cr0 & 1) | (op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + npxc = readmemw(easeg, eaaddr); + npxs = readmemw(easeg, eaaddr+2); + x87_settag(readmemw(easeg, eaaddr+4)); + TOP = (npxs >> 11) & 7; + eaaddr += 14; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + npxc = readmemw(easeg, eaaddr); + npxs = readmemw(easeg, eaaddr+4); + x87_settag(readmemw(easeg, eaaddr+8)); + TOP = (npxs >> 11) & 7; + eaaddr += 28; + break; + } + x87_ldmmx(&MM[0]); x87_ld_frstor(0); eaaddr += 10; + x87_ldmmx(&MM[1]); x87_ld_frstor(1); eaaddr += 10; + x87_ldmmx(&MM[2]); x87_ld_frstor(2); eaaddr += 10; + x87_ldmmx(&MM[3]); x87_ld_frstor(3); eaaddr += 10; + x87_ldmmx(&MM[4]); x87_ld_frstor(4); eaaddr += 10; + x87_ldmmx(&MM[5]); x87_ld_frstor(5); eaaddr += 10; + x87_ldmmx(&MM[6]); x87_ld_frstor(6); eaaddr += 10; + x87_ldmmx(&MM[7]); x87_ld_frstor(7); + + ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + if (MM[0].w[4] == 0xffff && MM[1].w[4] == 0xffff && MM[2].w[4] == 0xffff && MM[3].w[4] == 0xffff && + MM[4].w[4] == 0xffff && MM[5].w[4] == 0xffff && MM[6].w[4] == 0xffff && MM[7].w[4] == 0xffff && + !TOP && !(*(uint64_t *)tag)) + ismmx = 1; + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + if (fplog) pclog("FRSTOR %08X:%08X %i %i %04X\n", easeg, eaaddr, ismmx, TOP, x87_gettag()); + return abrt; +} +static int opFSTOR_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FSTOR(); + return abrt; +} +static int opFSTOR_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FSTOR(); + return abrt; +} + +static int FSAVE() +{ + FP_ENTER(); + if (fplog) pclog("FSAVE %08X:%08X %i\n", easeg, eaaddr, ismmx); + npxs = (npxs & ~(7 << 11)) | (TOP << 11); + + switch ((cr0&1)|(op32&0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,x87_gettag()); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+10,x87_op_off); + eaaddr+=14; + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st_fsave(0); eaaddr+=10; + x87_st_fsave(1); eaaddr+=10; + x87_st_fsave(2); eaaddr+=10; + x87_st_fsave(3); eaaddr+=10; + x87_st_fsave(4); eaaddr+=10; + x87_st_fsave(5); eaaddr+=10; + x87_st_fsave(6); eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,x87_gettag()); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+8,x87_pc_seg); + writememw(easeg,eaaddr+10,x87_op_off); + writememw(easeg,eaaddr+12,x87_op_seg); + eaaddr+=14; + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st_fsave(0); eaaddr+=10; + x87_st_fsave(1); eaaddr+=10; + x87_st_fsave(2); eaaddr+=10; + x87_st_fsave(3); eaaddr+=10; + x87_st_fsave(4); eaaddr+=10; + x87_st_fsave(5); eaaddr+=10; + x87_st_fsave(6); eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,x87_gettag()); + writememw(easeg,eaaddr+12,x87_pc_off); + writememw(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,(x87_op_off>>16)<<12); + eaaddr+=28; + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st_fsave(0); eaaddr+=10; + x87_st_fsave(1); eaaddr+=10; + x87_st_fsave(2); eaaddr+=10; + x87_st_fsave(3); eaaddr+=10; + x87_st_fsave(4); eaaddr+=10; + x87_st_fsave(5); eaaddr+=10; + x87_st_fsave(6); eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,x87_gettag()); + writememl(easeg,eaaddr+12,x87_pc_off); + writememl(easeg,eaaddr+16,x87_pc_seg); + writememl(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,x87_op_seg); + eaaddr+=28; + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st_fsave(0); eaaddr+=10; + x87_st_fsave(1); eaaddr+=10; + x87_st_fsave(2); eaaddr+=10; + x87_st_fsave(3); eaaddr+=10; + x87_st_fsave(4); eaaddr+=10; + x87_st_fsave(5); eaaddr+=10; + x87_st_fsave(6); eaaddr+=10; + x87_st_fsave(7); + } + break; + } + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + return abrt; +} +static int opFSAVE_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FSAVE(); + return abrt; +} +static int opFSAVE_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FSAVE(); + return abrt; +} + +static int opFSTSW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTSW %08X:%08X\n", easeg, eaaddr); + seteaw((npxs & 0xC7FF) | (TOP << 11)); + CLOCK_CYCLES(3); + return abrt; +} +static int opFSTSW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTSW %08X:%08X\n", easeg, eaaddr); + seteaw((npxs & 0xC7FF) | (TOP << 11)); + CLOCK_CYCLES(3); + return abrt; +} + + +static int opFLD(uint32_t fetchdat) +{ + int old_tag; + uint64_t old_i64; + + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLD %f\n", ST(fetchdat & 7)); + old_tag = tag[(TOP + fetchdat) & 7]; + old_i64 = ST_i64[(TOP + fetchdat) & 7]; + x87_push(ST(fetchdat&7)); + tag[TOP] = old_tag; + ST_i64[TOP] = old_i64; + CLOCK_CYCLES(4); + return 0; +} + +static int opFXCH(uint32_t fetchdat) +{ + double td; + uint8_t old_tag; + uint64_t old_i64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FXCH\n"); + td = ST(0); + ST(0) = ST(fetchdat&7); + ST(fetchdat&7) = td; + old_tag = tag[TOP]; + tag[TOP] = tag[(TOP + fetchdat) & 7]; + tag[(TOP + fetchdat) & 7] = old_tag; + old_i64 = ST_i64[TOP]; + ST_i64[TOP] = ST_i64[(TOP + fetchdat) & 7]; + ST_i64[(TOP + fetchdat) & 7] = old_i64; + + CLOCK_CYCLES(4); + return 0; +} + +static int opFCHS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCHS\n"); + ST(0) = -ST(0); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(6); + return 0; +} + +static int opFABS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FABS %f\n", ST(0)); + ST(0) = fabs(ST(0)); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(3); + return 0; +} + +static int opFTST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FTST\n"); + npxs &= ~(C0|C2|C3); + if (ST(0) == 0.0) npxs |= C3; + else if (ST(0) < 0.0) npxs |= C0; + CLOCK_CYCLES(4); + return 0; +} + +static int opFXAM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FXAM %i %f\n", tag[TOP&7], ST(0)); + npxs &= ~(C0|C1|C2|C3); + if (tag[TOP&7] == 3) npxs |= (C0|C3); + else if (ST(0) == 0.0) npxs |= C3; + else npxs |= C2; + if (ST(0) < 0.0) npxs |= C1; + CLOCK_CYCLES(8); + return 0; +} + +static int opFLD1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLD1\n"); + x87_push(1.0); + CLOCK_CYCLES(4); + return 0; +} + +static int opFLDL2T(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDL2T\n"); + x87_push(3.3219280948873623); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDL2E(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDL2E\n"); + x87_push(1.4426950408889634); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDPI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDPI\n"); + x87_push(3.141592653589793); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDEG2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDEG2\n"); + x87_push(0.3010299956639812); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDLN2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDLN2\n"); + x87_push(0.693147180559945); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDZ(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDZ\n"); + x87_push(0.0); + tag[TOP&7] = 1; + CLOCK_CYCLES(4); + return 0; +} + +static int opF2XM1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("F2XM1\n"); + ST(0) = pow(2.0, ST(0)) - 1.0; + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(200); + return 0; +} + +static int opFYL2X(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FYL2X\n"); + ST(1) = ST(1) * (log(ST(0)) / log(2.0)); + tag[(TOP + 1) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFYL2XP1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FYL2XP1\n"); + ST(1) = ST(1) * (log(ST(0)+1.0) / log(2.0)); + tag[(TOP + 1) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFPTAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPTAN\n"); + ST(0) = tan(ST(0)); + tag[TOP] &= ~TAG_UINT64; + x87_push(1.0); + npxs &= ~C2; + CLOCK_CYCLES(235); + return 0; +} + +static int opFPATAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPATAN\n"); + ST(1) = atan2(ST(1), ST(0)); + tag[(TOP + 1) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFDECSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDECSTP\n"); + TOP = (TOP - 1) & 7; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINCSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDECSTP\n"); + TOP = (TOP + 1) & 7; + CLOCK_CYCLES(4); + return 0; +} + +static int opFPREM(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPREM %f %f ", ST(0), ST(1)); + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + tag[TOP] &= ~TAG_UINT64; + if (fplog) pclog("%f\n", ST(0)); + npxs &= ~(C0|C1|C2|C3); + if (temp64 & 4) npxs|=C0; + if (temp64 & 2) npxs|=C3; + if (temp64 & 1) npxs|=C1; + CLOCK_CYCLES(100); + return 0; +} +static int opFPREM1(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPREM1 %f %f ", ST(0), ST(1)); + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + tag[TOP] &= ~TAG_UINT64; + if (fplog) pclog("%f\n", ST(0)); + npxs &= ~(C0|C1|C2|C3); + if (temp64 & 4) npxs|=C0; + if (temp64 & 2) npxs|=C3; + if (temp64 & 1) npxs|=C1; + CLOCK_CYCLES(100); + return 0; +} + +static int opFSQRT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSQRT\n"); + ST(0) = sqrt(ST(0)); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(83); + return 0; +} + +static int opFSINCOS(uint32_t fetchdat) +{ + double td; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSINCOS\n"); + td = ST(0); + ST(0) = sin(td); + tag[TOP] &= ~TAG_UINT64; + x87_push(cos(td)); + npxs &= ~C2; + CLOCK_CYCLES(330); + return 0; +} + +static int opFRNDINT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FRNDINT %g ", ST(0)); + ST(0) = (double)x87_fround(ST(0)); + tag[TOP] &= ~TAG_UINT64; + if (fplog) pclog("%g\n", ST(0)); + CLOCK_CYCLES(21); + return 0; +} + +static int opFSCALE(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSCALE\n"); + temp64 = (int64_t)ST(1); + ST(0) = ST(0) * pow(2.0, (double)temp64); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(30); + return 0; +} + +static int opFSIN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSIN\n"); + ST(0) = sin(ST(0)); + tag[TOP] &= ~TAG_UINT64; + npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} + +static int opFCOS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOS\n"); + ST(0) = cos(ST(0)); + tag[TOP] &= ~TAG_UINT64; + npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} + + +static int FLDENV() +{ + FP_ENTER(); + if (fplog) pclog("FLDENV %08X:%08X\n", easeg, eaaddr); + switch ((cr0 & 1) | (op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + npxc = readmemw(easeg, eaaddr); + npxs = readmemw(easeg, eaaddr+2); + x87_settag(readmemw(easeg, eaaddr+4)); + TOP = (npxs >> 11) & 7; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + npxc = readmemw(easeg, eaaddr); + npxs = readmemw(easeg, eaaddr+4); + x87_settag(readmemw(easeg, eaaddr+8)); + TOP = (npxs >> 11) & 7; + break; + } + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + return abrt; +} + +static int opFLDENV_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FLDENV(); + return abrt; +} +static int opFLDENV_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FLDENV(); + return abrt; +} + +static int opFLDCW_a16(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDCW %08X:%08X\n", easeg, eaaddr); + tempw = geteaw(); + if (abrt) return 1; + npxc = tempw; + CLOCK_CYCLES(4); + return 0; +} +static int opFLDCW_a32(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDCW %08X:%08X\n", easeg, eaaddr); + tempw = geteaw(); + if (abrt) return 1; + npxc = tempw; + CLOCK_CYCLES(4); + return 0; +} + +static int FSTENV() +{ + FP_ENTER(); + if (fplog) pclog("FSTENV %08X:%08X\n", easeg, eaaddr); + switch ((cr0 & 1) | (op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,x87_gettag()); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+10,x87_op_off); + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,x87_gettag()); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+8,x87_pc_seg); + writememw(easeg,eaaddr+10,x87_op_off); + writememw(easeg,eaaddr+12,x87_op_seg); + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,x87_gettag()); + writememw(easeg,eaaddr+12,x87_pc_off); + writememw(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,(x87_op_off>>16)<<12); + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,x87_gettag()); + writememl(easeg,eaaddr+12,x87_pc_off); + writememl(easeg,eaaddr+16,x87_pc_seg); + writememl(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,x87_op_seg); + break; + } + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + return abrt; +} + +static int opFSTENV_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FSTENV(); + return abrt; +} +static int opFSTENV_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FSTENV(); + return abrt; +} + +static int opFSTCW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTCW %08X:%08X\n", easeg, eaaddr); + seteaw(npxc); + CLOCK_CYCLES(3); + return abrt; +} +static int opFSTCW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTCW %08X:%08X\n", easeg, eaaddr); + seteaw(npxc); + CLOCK_CYCLES(3); + return abrt; +} + +#define opFCMOV(condition) \ + static int opFCMOV ## condition(uint32_t fetchdat) \ + { \ + FP_ENTER(); \ + cpu_state.pc++; \ + if (fplog) pclog("FCMOV %f\n", ST(fetchdat & 7)); \ + if (cond_ ## condition) \ + { \ + tag[TOP] = tag[(TOP + fetchdat) & 7]; \ + ST_i64[TOP] = ST_i64[(TOP + fetchdat) & 7]; \ + ST(0) = ST(fetchdat & 7); \ + } \ + CLOCK_CYCLES(4); \ + return 0; \ + } + +#define cond_U ( PF_SET()) +#define cond_NU (!PF_SET()) + +opFCMOV(B) +opFCMOV(E) +opFCMOV(BE) +opFCMOV(U) +opFCMOV(NB) +opFCMOV(NE) +opFCMOV(NBE) +opFCMOV(NU) diff --git a/src/xtide.c b/src/xtide.c new file mode 100644 index 000000000..5694cf78b --- /dev/null +++ b/src/xtide.c @@ -0,0 +1,58 @@ +#include "ibm.h" + +#include "io.h" +#include "ide.h" +#include "xtide.h" + +uint8_t xtide_high; + +void xtide_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port & 0xf) + { + case 0x0: + writeidew(0, val | (xtide_high << 8)); + return; + + case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + writeide(0, (port & 0xf) | 0x1f0, val); + return; + + case 0x8: + xtide_high = val; + return; + + case 0xe: + writeide(0, 0x3f6, val); + return; + } +} + +uint8_t xtide_read(uint16_t port, void *priv) +{ + uint16_t tempw; + switch (port & 0xf) + { + case 0x0: + tempw = readidew(0); + xtide_high = tempw >> 8; + return tempw & 0xff; + + case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + return readide(0, (port & 0xf) | 0x1f0); + + case 0x8: + return xtide_high; + + case 0xe: + return readide(0, 0x3f6); + } +} + +void xtide_init() +{ + ide_init(); + io_sethandler(0x0300, 0x0010, xtide_read, NULL, NULL, xtide_write, NULL, NULL, NULL); +} diff --git a/src/xtide.h b/src/xtide.h new file mode 100644 index 000000000..36e01c0a4 --- /dev/null +++ b/src/xtide.h @@ -0,0 +1 @@ +void xtide_init();